mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
04c0fc8aa7 | ||
|
|
1d8955fea5 | ||
|
|
48740a0dba | ||
|
|
4a404bd92e | ||
|
|
ff41701ddc | ||
|
|
2590c9c4a6 | ||
|
|
c5d61da5d2 | ||
|
|
5a622fd9db | ||
|
|
c83b1478e1 | ||
|
|
3243651c63 | ||
|
|
8d61cd9029 | ||
|
|
7fe49de420 | ||
|
|
a433096d5a | ||
|
|
b88e1e6970 | ||
|
|
79f228b04f | ||
|
|
d7cc1e6844 | ||
|
|
42312101b5 | ||
|
|
329f5b712a | ||
|
|
6ddd92c0a1 | ||
|
|
277dee109c | ||
|
|
ef71576825 | ||
|
|
c3271aa891 | ||
|
|
1cf17b5e78 | ||
|
|
2b6353b36e | ||
|
|
8b647f0977 | ||
|
|
4c31c5fab5 | ||
|
|
6ce878cb0d | ||
|
|
a67ba04c37 | ||
|
|
ae448e5ef9 | ||
|
|
a57826b125 | ||
|
|
656c460605 | ||
|
|
95534fa5c5 | ||
|
|
611e8b10c6 | ||
|
|
047852eb08 | ||
|
|
6318a08056 | ||
|
|
b60a92eed3 | ||
|
|
fe306a36b8 | ||
|
|
18870f8b62 | ||
|
|
9712ceedd7 | ||
|
|
2e32387e5c | ||
|
|
b66877c9df | ||
|
|
74a6f94e2b | ||
|
|
35fc8b7259 | ||
|
|
e591afd101 | ||
|
|
a41cdf4cfb | ||
|
|
ef72c42aa7 | ||
|
|
fbc814b54a | ||
|
|
4cfa3f879a | ||
|
|
4a8c7e869f | ||
|
|
a4a1c7a384 | ||
|
|
460315128b | ||
|
|
8ddafb4d9f | ||
|
|
ebda8f866c | ||
|
|
5ee4595aa8 | ||
|
|
5089ac6119 | ||
|
|
3f66f846cd | ||
|
|
279f21bb5b | ||
|
|
773ed97504 | ||
|
|
b6d4899d3f | ||
|
|
9d48ff7745 | ||
|
|
c4aab57c62 | ||
|
|
e8f27be200 | ||
|
|
15f0f967b3 | ||
|
|
cbafff8a71 | ||
|
|
41e362b580 | ||
|
|
622f59ad65 | ||
|
|
c5da38206e | ||
|
|
d737266f64 | ||
|
|
978c35995a | ||
|
|
2af7f2fa18 | ||
|
|
373c9090d3 | ||
|
|
723d407a87 | ||
|
|
dc90e6c3c3 | ||
|
|
68a2ed6776 | ||
|
|
7f32d4dc45 | ||
|
|
7b683fe258 | ||
|
|
72858175a2 | ||
|
|
9d7086067c | ||
|
|
5bb1da88ed | ||
|
|
9969a60b34 | ||
|
|
72402fa91e | ||
|
|
8255f3f9fe | ||
|
|
8957f77793 | ||
|
|
7187b82d1d | ||
|
|
1a92a58720 | ||
|
|
2351f9b9ad | ||
|
|
abc3c216f8 | ||
|
|
f1afa667d7 | ||
|
|
76d0671952 | ||
|
|
424769c32b | ||
|
|
f7249ad23a | ||
|
|
613d76c578 | ||
|
|
50662751fe | ||
|
|
c9e59e767a | ||
|
|
a7432bdea7 | ||
|
|
9ffad7f0db | ||
|
|
3097d5e093 | ||
|
|
cff4b5a5ee | ||
|
|
eda46e3949 | ||
|
|
71651718d4 | ||
|
|
da0cb44954 | ||
|
|
57621a93ad | ||
|
|
6a882f9dc6 | ||
|
|
c18b0eb122 | ||
|
|
3c28a66acf | ||
|
|
5c11de1663 | ||
|
|
72ea6bf414 | ||
|
|
101314a572 | ||
|
|
01f3e81a36 | ||
|
|
3cb3b6c400 | ||
|
|
8f58b58853 | ||
|
|
b66826169d | ||
|
|
d2a7376f14 | ||
|
|
c9e8a1cb4d | ||
|
|
8170f6f03f | ||
|
|
0abf88823f | ||
|
|
accf5a9a17 | ||
|
|
c64c81b7a3 | ||
|
|
7834028842 | ||
|
|
1e0d5eb238 | ||
|
|
b5460bd867 | ||
|
|
53cde90c8f | ||
|
|
d20a4db773 | ||
|
|
0f7677480f | ||
|
|
ba3930777a | ||
|
|
9c054a5774 | ||
|
|
cef0105dfc | ||
|
|
4773a1e77c | ||
|
|
ed4c7038b4 | ||
|
|
c4f31d3bb6 | ||
|
|
dc25e9b949 | ||
|
|
1f52b01b2c | ||
|
|
d5fc0fca41 | ||
|
|
212aa332dd | ||
|
|
17e7da77f0 | ||
|
|
201f0d3f5f | ||
|
|
7d0b3b300a | ||
|
|
0b55e205f7 | ||
|
|
9c0c6439cc | ||
|
|
d33d0301f8 | ||
|
|
6fd7f45cef | ||
|
|
57a937df03 | ||
|
|
ffd461dcf8 | ||
|
|
f77058774e | ||
|
|
1d0a726437 | ||
|
|
29bcbb0417 | ||
|
|
2d11c2cbb3 | ||
|
|
2edbcce032 | ||
|
|
35a53d9adb | ||
|
|
2885c2ce97 | ||
|
|
900c023bb5 | ||
|
|
12b95f6b93 | ||
|
|
85de3048a5 | ||
|
|
c1a9fe07e9 | ||
|
|
1a0da2e4ec | ||
|
|
38d11ecabe | ||
|
|
148762364b | ||
|
|
68d7596adf | ||
|
|
f005b7fd87 | ||
|
|
68ed683681 | ||
|
|
61e41595a2 | ||
|
|
484b574cef | ||
|
|
29695adf70 | ||
|
|
fac43811fd | ||
|
|
15f63d12d5 | ||
|
|
ba7b3fd60f | ||
|
|
897b9ccfe2 | ||
|
|
b97e1aa9fe | ||
|
|
d4a631446b | ||
|
|
a2cc053c6f | ||
|
|
8998ffc4e5 | ||
|
|
ca162716c6 | ||
|
|
629dd16714 | ||
|
|
12b903caf4 | ||
|
|
f9a0cf0cff | ||
|
|
070bcddf5a | ||
|
|
feb1e2bd48 | ||
|
|
6e7ee23644 | ||
|
|
c00cc18d37 | ||
|
|
a7e17a8855 | ||
|
|
60fa1db731 | ||
|
|
ac09ad3ffd | ||
|
|
27953e26b6 | ||
|
|
9375d9f603 | ||
|
|
72bd91c7f1 | ||
|
|
8850ca962e | ||
|
|
7fd590f855 | ||
|
|
5f7ae1fbce | ||
|
|
b56a25e89c | ||
|
|
4f32b093e6 | ||
|
|
6a54fb6f96 | ||
|
|
546ccd56c4 | ||
|
|
ca77a93214 | ||
|
|
ee1b20e1cd | ||
|
|
aa86e0bbc0 | ||
|
|
b6b3482010 | ||
|
|
05aecd2c0b | ||
|
|
6ab3d8f3ed | ||
|
|
0fcc7f2987 | ||
|
|
7d7e67b49b | ||
|
|
a41ea180fa | ||
|
|
98889b3f4e | ||
|
|
83fbfa8c71 | ||
|
|
a57262d6e7 | ||
|
|
fe708f045a | ||
|
|
8afcd67a1f | ||
|
|
16e258eb4c | ||
|
|
d6fbbddac9 | ||
|
|
9dc65df982 | ||
|
|
8f64e4a76f | ||
|
|
6e9008fb5a | ||
|
|
5ded80cf79 | ||
|
|
a6deee2083 | ||
|
|
e1f45dd84a | ||
|
|
9fd4541069 | ||
|
|
849487da23 | ||
|
|
dc64b43152 | ||
|
|
209a585a68 | ||
|
|
aa9cde22c8 | ||
|
|
faf7255e83 | ||
|
|
a6c97cc3bc | ||
|
|
977ceb404d | ||
|
|
b44efe7ef7 | ||
|
|
15ad3f46be | ||
|
|
c6d1a9858a | ||
|
|
77cc335c2d | ||
|
|
a95eb53684 | ||
|
|
910803e6db | ||
|
|
dd967f7769 | ||
|
|
b79ef672e1 | ||
|
|
70549e1a64 | ||
|
|
87e1c36e4a | ||
|
|
9991b19610 | ||
|
|
1381d3dbde | ||
|
|
5e575f5906 | ||
|
|
e2cbcd37d8 | ||
|
|
3b37b5b92d | ||
|
|
10b4678ee6 | ||
|
|
c1665818b9 | ||
|
|
27f4399c31 | ||
|
|
df52e481fb | ||
|
|
f93ae707e0 | ||
|
|
6ed10b7fde | ||
|
|
8208fe8a0e | ||
|
|
ace35b3e81 | ||
|
|
2b58e834ee | ||
|
|
14643643c9 | ||
|
|
7176aee852 | ||
|
|
c96a43b452 | ||
|
|
77915f78db | ||
|
|
c52f3349d1 | ||
|
|
6ab51de96d | ||
|
|
97cbc10925 | ||
|
|
65cd4f6047 | ||
|
|
174fd1bf0e | ||
|
|
b12413e42f | ||
|
|
7709130d93 | ||
|
|
15f7685755 | ||
|
|
83c6e9e821 | ||
|
|
1cacb1deab | ||
|
|
03bc8b7480 | ||
|
|
7d6668a3bd | ||
|
|
def40fab9b | ||
|
|
fceedd9f4d | ||
|
|
4272f2116e | ||
|
|
39d903375b | ||
|
|
9164eb03d5 | ||
|
|
7b789fe02a | ||
|
|
4ae3d3af71 | ||
|
|
6a54922044 | ||
|
|
466535abdc | ||
|
|
efacac2e3d | ||
|
|
74e16d85c5 | ||
|
|
39d7cbf412 | ||
|
|
8f7e463656 | ||
|
|
e6f345e45d | ||
|
|
d4f7f5297a | ||
|
|
9b8aebb00c | ||
|
|
58091edd68 | ||
|
|
18412f9322 | ||
|
|
1883ab29cb | ||
|
|
1a64c7d232 | ||
|
|
f3308d236b | ||
|
|
1b94e3b0e2 | ||
|
|
08b74e5ab9 | ||
|
|
5c966ec510 | ||
|
|
dc5c259069 | ||
|
|
dc27a179e2 | ||
|
|
236e6baa76 | ||
|
|
dba88bae3c | ||
|
|
d4b6e2b2b5 | ||
|
|
1e2d73fc80 | ||
|
|
ea3acc2d3a | ||
|
|
152505e879 | ||
|
|
8e6674066f | ||
|
|
8b2666cd04 | ||
|
|
afa8e4c786 | ||
|
|
ef211fc9e0 | ||
|
|
1a6c2fc55d | ||
|
|
15b40a97d9 | ||
|
|
343db78c03 | ||
|
|
4c1ae4701a | ||
|
|
05f213c266 | ||
|
|
0f617988d4 | ||
|
|
1e0b37f4bc | ||
|
|
991d8b178b | ||
|
|
608d5a87d1 | ||
|
|
914a6edd33 | ||
|
|
0cfa828572 | ||
|
|
4556b6c022 | ||
|
|
cba05480ba | ||
|
|
2abbae8dd0 | ||
|
|
f13bd1aec4 | ||
|
|
b6c21ad21a | ||
|
|
26301a4133 | ||
|
|
383f9832d4 | ||
|
|
50535a1894 | ||
|
|
ff31abe341 | ||
|
|
763f621d4c | ||
|
|
d922cae0a2 | ||
|
|
efaf375887 | ||
|
|
5932eae32a | ||
|
|
a331397954 | ||
|
|
a494ad5ec7 | ||
|
|
b617cd5549 | ||
|
|
e55338f927 | ||
|
|
6eadb8e771 | ||
|
|
f6048cc9c1 | ||
|
|
9fdb026e95 | ||
|
|
bf17bb4648 | ||
|
|
4dc1f40856 | ||
|
|
5302a9d0e6 | ||
|
|
e07e9390f6 | ||
|
|
a13eab55f5 | ||
|
|
b2228afd1a |
+1
-1
@@ -13,7 +13,7 @@ AllowShortBlocksOnASingleLine: true
|
|||||||
AllowShortCaseLabelsOnASingleLine: true
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: All
|
AllowShortFunctionsOnASingleLine: All
|
||||||
AllowShortIfStatementsOnASingleLine: true
|
AllowShortIfStatementsOnASingleLine: true
|
||||||
AllowShortLoopsOnASingleLine: false
|
AllowShortLoopsOnASingleLine: true
|
||||||
AlwaysBreakAfterDefinitionReturnType: None
|
AlwaysBreakAfterDefinitionReturnType: None
|
||||||
AlwaysBreakAfterReturnType: None
|
AlwaysBreakAfterReturnType: None
|
||||||
AlwaysBreakBeforeMultilineStrings: false
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
|||||||
@@ -3,3 +3,4 @@ exclude_paths:
|
|||||||
- '.github/**'
|
- '.github/**'
|
||||||
- 'ci/build_verilator.sh'
|
- 'ci/build_verilator.sh'
|
||||||
- 'include/vltstd/**'
|
- 'include/vltstd/**'
|
||||||
|
- 'nodist/fastcov.py'
|
||||||
|
|||||||
@@ -11,4 +11,6 @@ Thanks for taking the time to report this.
|
|||||||
|
|
||||||
Can you attach an example that shows the issue? (Must be openly licensed, ideally in test_regress format.)
|
Can you attach an example that shows the issue? (Must be openly licensed, ideally in test_regress format.)
|
||||||
|
|
||||||
May we assist you in trying to fix this yourself?
|
What 'verilator --version' are you using? Did you try it with the git master version?
|
||||||
|
|
||||||
|
Would you be willing to try to fix Verilator yourself with assistance?
|
||||||
|
|||||||
+91
-160
@@ -8,176 +8,107 @@
|
|||||||
|
|
||||||
version: ~> 1.0
|
version: ~> 1.0
|
||||||
|
|
||||||
os: linux
|
|
||||||
language: cpp
|
language: cpp
|
||||||
cache: ccache
|
|
||||||
|
|
||||||
env:
|
|
||||||
global:
|
|
||||||
- VERILATOR_CACHE=$HOME/verilator_cache
|
|
||||||
- VERILATOR_ROOT=$PWD
|
|
||||||
- VERILATOR_NUM_JOBS=$(echo `nproc` + 1 | bc)
|
|
||||||
- VERILATOR_CONFIG_FLAGS="--enable-maintainer-mode --enable-longtests"
|
|
||||||
- VERILATOR_AUTHOR_SITE=1
|
|
||||||
- OBJCACHE=ccache
|
|
||||||
|
|
||||||
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
|
||||||
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
|
||||||
- sudo apt-get install gdb gtkwave
|
|
||||||
- sudo apt-get install libgoogle-perftools-dev
|
|
||||||
before_script:
|
|
||||||
- bash -x ci/build_vcddiff.sh
|
|
||||||
- bash -x ci/build_verilator.sh
|
|
||||||
after_script:
|
|
||||||
- ccache -s
|
|
||||||
|
|
||||||
|
# The list and order of build stages
|
||||||
stages:
|
stages:
|
||||||
- "Build Verilator"
|
- build # Build Verilator
|
||||||
- test
|
- test # Run tests
|
||||||
|
|
||||||
|
# Dump info about the environment for debugging
|
||||||
|
before_install:
|
||||||
|
# To dump the script that Travis itself is executing, add 'cat $0' here
|
||||||
|
- cd "$TRAVIS_BUILD_DIR" # Skipping the git clone in later stages requires this
|
||||||
|
- export CCACHE_MAXSIZE=$(ci/travis-ccache-size.bash) # Set here after the 'cd'
|
||||||
|
- env | sort
|
||||||
|
- ls -lA .
|
||||||
|
- ls -lA bin
|
||||||
|
- g++ -E -dM -c -x c++ /dev/null | sort
|
||||||
|
- clang++ -E -dM -c -x c++ /dev/null | sort
|
||||||
|
|
||||||
|
# Install all dependencies
|
||||||
|
install:
|
||||||
|
- ./ci/travis-install.bash
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
# ccache maintenance
|
||||||
|
- ./ci/travis-ccache-maint.bash
|
||||||
|
# On Focal, set the SystemC installation location
|
||||||
|
- |
|
||||||
|
if [ "$TRAVIS_DIST" = "focal" ]; then
|
||||||
|
export SYSTEMC_INCLUDE=/usr/include
|
||||||
|
export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu
|
||||||
|
fi
|
||||||
|
|
||||||
|
before_cache:
|
||||||
|
- ccache -s -z
|
||||||
|
|
||||||
|
# All jobs run the same script
|
||||||
|
script: ./ci/travis-script.bash
|
||||||
|
|
||||||
|
# Enumerate all the jobs
|
||||||
jobs:
|
jobs:
|
||||||
include:
|
include:
|
||||||
- if: type != cron
|
############################################################################
|
||||||
stage: "Build Verilator"
|
# Jobs in the 'build' stage
|
||||||
name: Build Verilator
|
############################################################################
|
||||||
compiler: gcc
|
# GCC builds
|
||||||
script: echo "Done building Verilator"
|
- {stage: build, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {create: {name: trusty-gcc, paths: .}}}
|
||||||
# Non-cron build will just run on whatever linux flavor we get
|
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {create: {name: xenial-gcc, paths: .}}}
|
||||||
- if: type != cron
|
- {stage: build, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {create: {name: bionic-gcc, paths: .}}}
|
||||||
stage: test
|
- {stage: build, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc, paths: .}}}
|
||||||
name: Dist test
|
# Clang builds
|
||||||
compiler: gcc
|
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {create: {name: xenial-clang, paths: .}}}
|
||||||
script: ci/test.sh dist
|
- {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}}
|
||||||
- if: type != cron
|
# Coverage build
|
||||||
stage: test
|
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1}
|
||||||
name: Vlt test
|
############################################################################
|
||||||
compiler: gcc
|
# Jobs in the 'test' stage
|
||||||
script: ci/test.sh vlt
|
############################################################################
|
||||||
- if: type != cron
|
# GCC tests
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
name: Vltmt set 0 test
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
script: ci/test.sh vltmt0
|
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
- if: type != cron
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
name: Vltmt set 1 test
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
script: ci/test.sh vltmt1
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
# Cron builds try different OS/compiler combinations
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
stage: "Build Verilator"
|
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
name: Build xenial gcc Verilator
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
os: linux
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
script: echo "Done building Verilator"
|
# Clang tests
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
name: Xenial gcc dist test
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||||
script: ci/test.sh dist
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||||
- if: type = cron
|
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||||
stage: test
|
# Coverage tests
|
||||||
name: Xenial gcc vlt test
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-dist}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-0}
|
||||||
dist: xenial
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-1}
|
||||||
compiler: gcc
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-2}
|
||||||
script: ci/test.sh vlt
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-3}
|
||||||
- if: type = cron
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-0}
|
||||||
stage: test
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
|
||||||
name: Xenial gcc vltmt test
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
|
||||||
os: linux
|
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
|
||||||
dist: xenial
|
|
||||||
compiler: gcc
|
|
||||||
script: ci/test.sh vltmt
|
|
||||||
- if: type = cron
|
|
||||||
stage: "Build Verilator"
|
|
||||||
name: Build xenial clang Verilator
|
|
||||||
os: linux
|
|
||||||
dist: xenial
|
|
||||||
compiler: clang
|
|
||||||
script: echo "Done building Verilator"
|
|
||||||
- if: type = cron
|
|
||||||
stage: test
|
|
||||||
name: Xenial clang dist test
|
|
||||||
os: linux
|
|
||||||
dist: xenial
|
|
||||||
compiler: clang
|
|
||||||
script: ci/test.sh dist
|
|
||||||
- if: type = cron
|
|
||||||
stage: test
|
|
||||||
name: Xenial clang vlt test
|
|
||||||
os: linux
|
|
||||||
dist: xenial
|
|
||||||
compiler: clang
|
|
||||||
script: ci/test.sh vlt
|
|
||||||
- if: type = cron
|
|
||||||
stage: test
|
|
||||||
name: Xenial clang vltmt test
|
|
||||||
os: linux
|
|
||||||
dist: xenial
|
|
||||||
compiler: clang
|
|
||||||
script: ci/test.sh vltmt
|
|
||||||
# - if: type = cron
|
|
||||||
# stage: "Build Verilator"
|
|
||||||
# name: Build OSX gcc Verilator
|
|
||||||
# os: osx
|
|
||||||
# compiler: gcc
|
|
||||||
# script: echo "Done building Verilator"
|
|
||||||
# - if: type = cron
|
|
||||||
# stage: test
|
|
||||||
# name: OSX gcc dist test
|
|
||||||
# os: osx
|
|
||||||
# compiler: gcc
|
|
||||||
# script: ci/test.sh dist
|
|
||||||
# - if: type = cron
|
|
||||||
# stage: test
|
|
||||||
# name: OSX gcc vlt test
|
|
||||||
# os: osx
|
|
||||||
# compiler: gcc
|
|
||||||
# script: ci/test.sh vlt
|
|
||||||
# - if: type = cron
|
|
||||||
# stage: test
|
|
||||||
# name: OSX gcc vltmt test
|
|
||||||
# os: osx
|
|
||||||
# compiler: gcc
|
|
||||||
# script: ci/test.sh vltmt
|
|
||||||
- if: type = cron
|
|
||||||
stage: "Build Verilator"
|
|
||||||
name: Build trusty gcc Verilator
|
|
||||||
os: linux
|
|
||||||
dist: trusty
|
|
||||||
compiler: gcc
|
|
||||||
script: echo "Done building Verilator"
|
|
||||||
- if: type = cron
|
|
||||||
stage: test
|
|
||||||
name: Trusty gcc dist test
|
|
||||||
os: linux
|
|
||||||
dist: trusty
|
|
||||||
compiler: gcc
|
|
||||||
script: ci/test.sh dist
|
|
||||||
- if: type = cron
|
|
||||||
stage: test
|
|
||||||
name: Trusty gcc vlt test
|
|
||||||
os: linux
|
|
||||||
dist: trusty
|
|
||||||
compiler: gcc
|
|
||||||
script: ci/test.sh vlt
|
|
||||||
- if: type = cron
|
|
||||||
stage: test
|
|
||||||
os: linux
|
|
||||||
dist: trusty
|
|
||||||
name: Trusty gcc vltmt test
|
|
||||||
compiler: gcc
|
|
||||||
script: ci/test.sh vltmt
|
|
||||||
|
|
||||||
notifications:
|
notifications:
|
||||||
email:
|
email:
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ src/Makefile$
|
|||||||
src/Makefile_obj$
|
src/Makefile_obj$
|
||||||
include/verilated.mk$
|
include/verilated.mk$
|
||||||
test_regress/.gdbinit$
|
test_regress/.gdbinit$
|
||||||
|
codecov.yml
|
||||||
config.cache$
|
config.cache$
|
||||||
config.status$
|
config.status$
|
||||||
verilator\.log
|
verilator\.log
|
||||||
|
|||||||
+10
-1
@@ -336,6 +336,7 @@ installdata:
|
|||||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c
|
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c
|
||||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc
|
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc
|
||||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib
|
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib
|
||||||
|
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/xml_py
|
||||||
cd $(srcdir) \
|
cd $(srcdir) \
|
||||||
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
|
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
|
||||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||||
@@ -370,8 +371,8 @@ uninstall:
|
|||||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c
|
||||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc
|
||||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib
|
||||||
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples/xml_py
|
||||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
||||||
-rmdir $(DESTDIR)$(pkgdatadir)/cmake
|
|
||||||
-rmdir $(DESTDIR)$(pkgdatadir)
|
-rmdir $(DESTDIR)$(pkgdatadir)
|
||||||
-rmdir $(DESTDIR)$(pkgconfigdir)
|
-rmdir $(DESTDIR)$(pkgconfigdir)
|
||||||
|
|
||||||
@@ -455,6 +456,14 @@ analyzer-include:
|
|||||||
-rm -rf examples/*/obj*
|
-rm -rf examples/*/obj*
|
||||||
scan-build $(MAKE) -k examples
|
scan-build $(MAKE) -k examples
|
||||||
|
|
||||||
|
CLANGFORMAT = clang-format
|
||||||
|
CLANGFORMAT_FLAGS = -i
|
||||||
|
|
||||||
|
clang-format:
|
||||||
|
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|
||||||
|
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
|
||||||
|
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H)
|
||||||
|
|
||||||
ftp: info
|
ftp: info
|
||||||
|
|
||||||
install-msg:
|
install-msg:
|
||||||
|
|||||||
+24
-21
@@ -4,7 +4,8 @@
|
|||||||
ifdef::env-github[]
|
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/48478c986f13400682ffe4a5e0939b3a[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 free 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
|
||||||
@@ -56,7 +57,7 @@ endif::[]
|
|||||||
== What Verilator Does
|
== What Verilator Does
|
||||||
|
|
||||||
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
|
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
|
||||||
"Verilates" the specified synthesizable Verilog or SystemVerilog code by
|
"Verilates" the specified Verilog or SystemVerilog code by
|
||||||
reading it, performing lint checks, and optionally inserting assertion
|
reading it, performing lint checks, and optionally inserting assertion
|
||||||
checks and coverage-analysis points. It outputs single- or multi-threaded
|
checks and coverage-analysis points. It outputs single- or multi-threaded
|
||||||
.cpp and .h files, the "Verilated" code.
|
.cpp and .h files, the "Verilated" code.
|
||||||
@@ -72,30 +73,30 @@ Verilator may not be the best choice if you are expecting a full featured
|
|||||||
replacement for NC-Verilog, VCS or another commercial Verilog simulator, or
|
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 synthesizable
|
this.) However, if you are looking for a path to migrate SystemVerilog to
|
||||||
Verilog 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,
|
||||||
than only translate, Verilator compiles your code into a much faster
|
Verilator compiles your code into a much faster optimized and optionally
|
||||||
optimized and optionally thread-partitioned model, which is in turn wrapped
|
thread-partitioned model, which is in turn wrapped inside a
|
||||||
inside a {cpp}/SystemC/{cpp}-under-Python module. The results are a compiled Verilog
|
{cpp}/SystemC module. The results are a compiled
|
||||||
model that executes even on a single-thread over 10x faster than standalone
|
Verilog model that executes even on a single-thread over 10x faster than
|
||||||
SystemC, and on a single thread is about 100 times faster than interpreted
|
standalone SystemC, and on a single thread is about 100 times faster than
|
||||||
Verilog simulators such as http://iverilog.icarus.com[Icarus
|
interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus
|
||||||
Verilog]. Another 2-10x speedup might be gained from multithreading
|
Verilog]. Another 2-10x speedup might be gained from multithreading
|
||||||
(yielding 200-1000x total over interpreted simulators).
|
(yielding 200-1000x total over interpreted simulators).
|
||||||
|
|
||||||
Verilator has typically similar or better performance versus the commercial
|
Verilator has typically similar or better performance versus the
|
||||||
Verilog simulators (Carbon Design Systems Carbonator, Modelsim, Cadence
|
closed-source Verilog simulators (Carbon Design Systems Carbonator,
|
||||||
Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic CVer/CVC). But,
|
Modelsim, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic
|
||||||
Verilator is free, so you can spend on computes rather than licenses. Thus
|
CVer/CVC). But, Verilator is open-sourced, so you can spend on computes
|
||||||
Verilator gives you more cycles/dollar than anything else available.
|
rather than licenses. Thus Verilator gives you the best cycles/dollar.
|
||||||
|
|
||||||
For more information on how Verilator stacks up to some of the other
|
For more information on how Verilator stacks up to some of the other
|
||||||
commercial and free Verilog simulators, see the
|
closed-sourced and open-sourced Verilog simulators, see the
|
||||||
https://www.veripool.org/verilog_sim_benchmarks.html[Verilog Simulator
|
https://www.veripool.org/verilog_sim_benchmarks.html[Verilog Simulator
|
||||||
Benchmarks]. (If you benchmark Verilator, please see the notes in the
|
Benchmarks]. (If you benchmark Verilator, please see the notes in the
|
||||||
https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)], and also
|
https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)], and also
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
+425
-262
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"
|
||||||
|
|||||||
+14
-11
@@ -6,20 +6,23 @@
|
|||||||
# 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 \
|
||||||
flex=2.6.4-6 \
|
ccache \
|
||||||
git=1:2.17.1-1ubuntu0.5 \
|
flex \
|
||||||
libfl-dev=2.6.4-6 \
|
git \
|
||||||
perl=5.26.1-6ubuntu0.3 \
|
libfl-dev \
|
||||||
python3=3.6.7-1~18.04 \
|
libgoogle-perftools-dev \
|
||||||
|
perl \
|
||||||
|
python3 \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -rf /var/lib/apt/lists/*
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|||||||
-34
@@ -1,34 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
# DESCRIPTION: Verilator: Travis CI test script
|
|
||||||
#
|
|
||||||
# Copyright 2019 by Todd Strader. This program is free software; you
|
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
export DRIVER_FLAGS='-j 0 --quiet --rerun'
|
|
||||||
|
|
||||||
case $1 in
|
|
||||||
dist)
|
|
||||||
make -C test_regress SCENARIOS=--dist
|
|
||||||
;;
|
|
||||||
vlt)
|
|
||||||
make -C test_regress SCENARIOS=--vlt
|
|
||||||
;;
|
|
||||||
vltmt)
|
|
||||||
make -C test_regress SCENARIOS=--vltmt
|
|
||||||
;;
|
|
||||||
vltmt0)
|
|
||||||
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
|
|
||||||
;;
|
|
||||||
vltmt1)
|
|
||||||
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Usage: test.sh (dist|vlt|vltmt)"
|
|
||||||
exit -1
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
Executable
+29
@@ -0,0 +1,29 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# DESCRIPTION: Verilator: Travis CI ccache maintenance
|
||||||
|
#
|
||||||
|
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# This script is run in 'before_script', once ccache has been set up.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# Show version
|
||||||
|
ccache --version
|
||||||
|
|
||||||
|
# Flush ccache if requested in commit message
|
||||||
|
COMMIT="${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}"
|
||||||
|
if git log --format=%B -n 1 "$COMMIT" | grep -q -i '\[travis\s\+ccache\s\+clear\]'; then
|
||||||
|
echo "Flushing ccache due to commit message"
|
||||||
|
ccache -C
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Dump stats, then zero stats
|
||||||
|
ccache -s -z
|
||||||
Executable
+37
@@ -0,0 +1,37 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# DESCRIPTION: Verilator: Travis CI ccache sizer
|
||||||
|
#
|
||||||
|
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# This script computes the size of the ccache to be used for a job. We want the
|
||||||
|
# ccache to be just big enough to be able to hold a whole build so a re-build
|
||||||
|
# of the same does not miss in the cache due to capacity, but we don't want the
|
||||||
|
# ccache too big as pulling it down from the network takes time, and it is
|
||||||
|
# unlikely objects from much earlier builds would be useful.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
fatal() {
|
||||||
|
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||||
|
if [ "$COVERAGE" == 1 ]; then
|
||||||
|
echo "1024M"
|
||||||
|
else
|
||||||
|
echo "768M"
|
||||||
|
fi
|
||||||
|
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||||
|
if [[ $TESTS == coverage-* ]]; then
|
||||||
|
echo "1536M"
|
||||||
|
else
|
||||||
|
echo "256M"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
|
||||||
|
fi
|
||||||
Executable
+72
@@ -0,0 +1,72 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# DESCRIPTION: Verilator: Travis CI dependency install script
|
||||||
|
#
|
||||||
|
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# This script runs in the 'install' phase of all jobs, in all stages. We try to
|
||||||
|
# minimize the time spent in this by selectively installing only the components
|
||||||
|
# required by the particular build stage.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
# Note that Travis runs "apt-get update" when "apt-get install" is used in the
|
||||||
|
# .travis.yml file directly, but since we invoke it via this script, we need to
|
||||||
|
# run it manually where requried, otherwise some packages cannot be found.
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
fatal() {
|
||||||
|
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
install-vcddiff() {
|
||||||
|
TMP_DIR="$(mktemp -d)"
|
||||||
|
git clone https://github.com/veripool/vcddiff "$TMP_DIR"
|
||||||
|
git -C "${TMP_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
|
||||||
|
make -C "${TMP_DIR}"
|
||||||
|
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
|
||||||
|
# build Verilator
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
time sudo apt-get update
|
||||||
|
sudo apt-get install libfl-dev
|
||||||
|
sudo apt-get install libgoogle-perftools-dev
|
||||||
|
if [ "$COVERAGE" = 1 ]; then
|
||||||
|
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
|
||||||
|
# run the tests
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install gdb gtkwave lcov
|
||||||
|
if [ "$TRAVIS_DIST" = "focal" ]; then
|
||||||
|
sudo apt-get install libsystemc-dev
|
||||||
|
fi
|
||||||
|
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
||||||
|
# Not listing Bit::Vector as slow to install, and only skips one test
|
||||||
|
install-vcddiff
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
##############################################################################
|
||||||
|
# Unknown build stage
|
||||||
|
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
|
||||||
|
fi
|
||||||
Executable
+101
@@ -0,0 +1,101 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# DESCRIPTION: Verilator: Travis CI main job script
|
||||||
|
#
|
||||||
|
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# This is the main script executed in the 'script' phase by all jobs. We use a
|
||||||
|
# single script to keep the .travis.yml spec simple. We pass job parameters via
|
||||||
|
# environment variables using 'env' keys. Having different 'env' keys in jobs
|
||||||
|
# ensures they use different Travis build caches.
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
set -e
|
||||||
|
set -x
|
||||||
|
|
||||||
|
fatal() {
|
||||||
|
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Build verilator
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
if [ "$COVERAGE" != 1 ]; then
|
||||||
|
autoconf
|
||||||
|
./configure --enable-longtests --enable-ccwarn
|
||||||
|
make -j $(nproc)
|
||||||
|
else
|
||||||
|
nodist/code_coverage --stages 1-2
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||||
|
##############################################################################
|
||||||
|
# Run tests
|
||||||
|
|
||||||
|
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||||
|
# Run the specified test
|
||||||
|
case $TESTS in
|
||||||
|
dist-vlt-0)
|
||||||
|
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
|
||||||
|
;;
|
||||||
|
dist-vlt-1)
|
||||||
|
make -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
|
||||||
|
;;
|
||||||
|
vltmt-0)
|
||||||
|
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
|
||||||
|
;;
|
||||||
|
vltmt-1)
|
||||||
|
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
|
||||||
|
;;
|
||||||
|
coverage-dist)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--dist
|
||||||
|
;;
|
||||||
|
coverage-vlt-0)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
|
||||||
|
;;
|
||||||
|
coverage-vlt-1)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
|
||||||
|
;;
|
||||||
|
coverage-vlt-2)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
|
||||||
|
;;
|
||||||
|
coverage-vlt-3)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
|
||||||
|
;;
|
||||||
|
coverage-vltmt-0)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
|
||||||
|
;;
|
||||||
|
coverage-vltmt-1)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
|
||||||
|
;;
|
||||||
|
coverage-vltmt-2)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
|
||||||
|
;;
|
||||||
|
coverage-vltmt-3)
|
||||||
|
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
fatal "Unknown test: $TESTS"
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
# Upload coverage data to codecov.io
|
||||||
|
if [[ $TESTS == coverage-* ]]; then
|
||||||
|
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
##############################################################################
|
||||||
|
# Unknown build stage
|
||||||
|
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
|
||||||
|
fi
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
# DESCRIPTION: codecov.io config
|
||||||
|
#
|
||||||
|
# Copyright 2020-2020 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
####################
|
||||||
|
# Validate:
|
||||||
|
# curl --data-binary @codecov.yml https://codecov.io/validate
|
||||||
|
|
||||||
|
codecov:
|
||||||
|
require_ci_to_pass: no
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
precision: 2
|
||||||
|
round: down
|
||||||
|
range: "70...100"
|
||||||
|
ignore:
|
||||||
|
- "ci"
|
||||||
|
- "docs"
|
||||||
|
- "examples"
|
||||||
|
- "include/gtkwave"
|
||||||
|
- "include/vltstd"
|
||||||
|
- "test_regress"
|
||||||
|
|
||||||
|
parsers:
|
||||||
|
gcov:
|
||||||
|
branch_detection:
|
||||||
|
conditional: yes
|
||||||
|
loop: yes
|
||||||
|
method: no
|
||||||
|
macro: no
|
||||||
|
|
||||||
|
comment:
|
||||||
|
layout: "reach,diff,flags,tree"
|
||||||
|
behavior: default
|
||||||
|
require_changes: yes
|
||||||
+26
-1
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||||
#AC_INIT([Verilator],[#.### devel])
|
#AC_INIT([Verilator],[#.### devel])
|
||||||
AC_INIT([Verilator],[4.032 2020-04-04],
|
AC_INIT([Verilator],[4.036 2020-06-06],
|
||||||
[https://verilator.org],
|
[https://verilator.org],
|
||||||
[verilator],[https://verilator.org])
|
[verilator],[https://verilator.org])
|
||||||
# When releasing, also update header of Changes file
|
# When releasing, also update header of Changes file
|
||||||
@@ -16,7 +16,10 @@ AC_INIT([Verilator],[4.032 2020-04-04],
|
|||||||
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],
|
||||||
@@ -159,6 +162,12 @@ 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
|
||||||
|
|
||||||
|
AC_CHECK_PROG(OBJCACHE,ccache,ccache)
|
||||||
|
if test "x$OBJCACHE" != "x" ; then
|
||||||
|
objcache_version=$($OBJCACHE --version | head -1)
|
||||||
|
AC_MSG_RESULT([objcache is $OBJCACHE --version = $objcache_version])
|
||||||
|
fi
|
||||||
|
|
||||||
# Checks for libraries.
|
# Checks for libraries.
|
||||||
|
|
||||||
# Checks for typedefs, structures
|
# Checks for typedefs, structures
|
||||||
@@ -328,6 +337,7 @@ m4_foreach([cflag],[
|
|||||||
[-mno-cet],
|
[-mno-cet],
|
||||||
[-Qunused-arguments],
|
[-Qunused-arguments],
|
||||||
[-Wno-bool-operation],
|
[-Wno-bool-operation],
|
||||||
|
[-Wno-tautological-bitwise-compare],
|
||||||
[-Wno-parentheses-equality],
|
[-Wno-parentheses-equality],
|
||||||
[-Wno-sign-compare],
|
[-Wno-sign-compare],
|
||||||
[-Wno-uninitialized],
|
[-Wno-uninitialized],
|
||||||
@@ -409,6 +419,7 @@ AC_LINK_IFELSE(
|
|||||||
CFG_WITH_THREADED=$_my_result
|
CFG_WITH_THREADED=$_my_result
|
||||||
AC_SUBST(CFG_WITH_THREADED)
|
AC_SUBST(CFG_WITH_THREADED)
|
||||||
AC_MSG_RESULT($CFG_WITH_THREADED)
|
AC_MSG_RESULT($CFG_WITH_THREADED)
|
||||||
|
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||||
|
|
||||||
# Check compiler flag
|
# Check compiler flag
|
||||||
if test "$CFG_WITH_THREADED" = "no" ; then
|
if test "$CFG_WITH_THREADED" = "no" ; then
|
||||||
@@ -431,6 +442,20 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
|
|||||||
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
|
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
|
||||||
[], [#include <sys/stat.h>])
|
[], [#include <sys/stat.h>])
|
||||||
|
|
||||||
|
# HAVE_SYSTEMC
|
||||||
|
# - If found the default search path has it, so support is always enabled.
|
||||||
|
# - If not found or not system-wide, user can set SYSTEMC_INCLUDE.
|
||||||
|
# AC_CHECK_HEADERS seems to not locate on Travis-CI but include does work.
|
||||||
|
AC_MSG_CHECKING([whether SystemC is found (in system path)])
|
||||||
|
AC_COMPILE_IFELSE(
|
||||||
|
[AC_LANG_PROGRAM([[#include <systemc.h>
|
||||||
|
]],[])],
|
||||||
|
[_my_result=yes
|
||||||
|
AC_DEFINE([HAVE_SYSTEMC_H],[1],[Defined if have systemc.h])],
|
||||||
|
[_my_result=no])
|
||||||
|
AC_MSG_RESULT($_my_result)
|
||||||
|
AC_SUBST(HAVE_SYSTEMC_H)
|
||||||
|
|
||||||
# Checks for system services
|
# Checks for system services
|
||||||
|
|
||||||
# Other install directories
|
# Other install directories
|
||||||
|
|||||||
+26
-4
@@ -1,44 +1,66 @@
|
|||||||
The contributors listed below have certified their Verilator contributions
|
The contributors listed below have certified their Verilator contributions
|
||||||
under the Developer Certificate of Origin
|
under the Developer Certificate of Origin (https://developercertificate.org/).
|
||||||
(https://developercertificate.org/).
|
|
||||||
|
|
||||||
Please see the Verilator manual for 200+ additional contributors. Thanks to
|
Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
||||||
all.
|
|
||||||
|
|
||||||
Ahmed El-Mahmoudy
|
Ahmed El-Mahmoudy
|
||||||
Alex Chadwick
|
Alex Chadwick
|
||||||
Chris Randall
|
Chris Randall
|
||||||
|
Dan Petrisko
|
||||||
|
David Horton
|
||||||
David Stanford
|
David Stanford
|
||||||
Driss Hafdi
|
Driss Hafdi
|
||||||
Eric Rippey
|
Eric Rippey
|
||||||
Garrett Smith
|
Garrett Smith
|
||||||
Geza Lore
|
Geza Lore
|
||||||
Gianfranco Costamagna
|
Gianfranco Costamagna
|
||||||
|
Glen Gibb
|
||||||
Howard Su
|
Howard Su
|
||||||
|
Huang Rui
|
||||||
Iztok Jeras
|
Iztok Jeras
|
||||||
|
James Hanlon
|
||||||
|
James Hutchinson
|
||||||
|
Jamey Hicks
|
||||||
|
Jan Van Winkel
|
||||||
Jeremy Bennett
|
Jeremy Bennett
|
||||||
John Coiner
|
John Coiner
|
||||||
|
John Demme
|
||||||
Julien Margetts
|
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 Myers
|
||||||
Patrick Stewart
|
Patrick Stewart
|
||||||
|
Peter Horvath
|
||||||
Peter Monsson
|
Peter Monsson
|
||||||
Philipp Wagner
|
Philipp Wagner
|
||||||
Pieter Kapsenberg
|
Pieter Kapsenberg
|
||||||
|
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
|
||||||
Wilson Snyder
|
Wilson Snyder
|
||||||
|
Yossi Nivin
|
||||||
|
Yuri Victorovich
|
||||||
Yutetsu TAKATSUKASA
|
Yutetsu TAKATSUKASA
|
||||||
Yves Mathieu
|
Yves Mathieu
|
||||||
|
|||||||
@@ -1,159 +0,0 @@
|
|||||||
clang-format is used to standardize the indentation of the internal C++
|
|
||||||
code.
|
|
||||||
|
|
||||||
For the most part clang-format changes provide good consistency, the two
|
|
||||||
main exceptions being the indentation of preprocessor directives, and
|
|
||||||
tables of statements.
|
|
||||||
|
|
||||||
Reformatting is generally performed only before other large changes are to
|
|
||||||
be made to a file. The following files are not yet clang-format clean:
|
|
||||||
|
|
||||||
clang-format -i include/verilated.h
|
|
||||||
clang-format -i include/verilated_dpi.h
|
|
||||||
clang-format -i include/verilated_fst_c.h
|
|
||||||
clang-format -i include/verilated_heavy.h
|
|
||||||
clang-format -i include/verilated_imp.h
|
|
||||||
clang-format -i include/verilated_save.h
|
|
||||||
clang-format -i include/verilated_sym_props.h
|
|
||||||
clang-format -i include/verilated_unordered_set_map.h
|
|
||||||
clang-format -i include/verilated_vcd_c.h
|
|
||||||
clang-format -i include/verilatedos.h
|
|
||||||
|
|
||||||
clang-format -i include/verilated.cpp
|
|
||||||
clang-format -i include/verilated_cov.cpp
|
|
||||||
clang-format -i include/verilated_dpi.cpp
|
|
||||||
clang-format -i include/verilated_fst_c.cpp
|
|
||||||
clang-format -i include/verilated_save.cpp
|
|
||||||
clang-format -i include/verilated_threads.cpp
|
|
||||||
clang-format -i include/verilated_vcd_c.cpp
|
|
||||||
clang-format -i include/verilated_vpi.cpp
|
|
||||||
|
|
||||||
clang-format -i src/V3Ast.h
|
|
||||||
clang-format -i src/V3AstNodes.h
|
|
||||||
clang-format -i src/V3EmitCBase.h
|
|
||||||
clang-format -i src/V3Error.h
|
|
||||||
clang-format -i src/V3File.h
|
|
||||||
clang-format -i src/V3FileLine.h
|
|
||||||
clang-format -i src/V3Global.h
|
|
||||||
clang-format -i src/V3Graph.h
|
|
||||||
clang-format -i src/V3GraphDfa.h
|
|
||||||
clang-format -i src/V3GraphStream.h
|
|
||||||
clang-format -i src/V3Hashed.h
|
|
||||||
clang-format -i src/V3LanguageWords.h
|
|
||||||
clang-format -i src/V3LinkDot.h
|
|
||||||
clang-format -i src/V3List.h
|
|
||||||
clang-format -i src/V3Number.h
|
|
||||||
clang-format -i src/V3Options.h
|
|
||||||
clang-format -i src/V3OrderGraph.h
|
|
||||||
clang-format -i src/V3Os.h
|
|
||||||
clang-format -i src/V3ParseImp.h
|
|
||||||
clang-format -i src/V3ParseSym.h
|
|
||||||
clang-format -i src/V3Partition.h
|
|
||||||
clang-format -i src/V3PartitionGraph.h
|
|
||||||
clang-format -i src/V3PreLex.h
|
|
||||||
clang-format -i src/V3PreProc.h
|
|
||||||
clang-format -i src/V3Scoreboard.h
|
|
||||||
clang-format -i src/V3SenTree.h
|
|
||||||
clang-format -i src/V3Simulate.h
|
|
||||||
clang-format -i src/V3Stats.h
|
|
||||||
clang-format -i src/V3String.h
|
|
||||||
clang-format -i src/V3SymTable.h
|
|
||||||
clang-format -i src/V3TSP.h
|
|
||||||
clang-format -i src/V3Task.h
|
|
||||||
clang-format -i src/V3WidthCommit.h
|
|
||||||
|
|
||||||
clang-format -i src/V3Active.cpp
|
|
||||||
clang-format -i src/V3ActiveTop.cpp
|
|
||||||
clang-format -i src/V3Assert.cpp
|
|
||||||
clang-format -i src/V3AssertPre.cpp
|
|
||||||
clang-format -i src/V3Ast.cpp
|
|
||||||
clang-format -i src/V3AstNodes.cpp
|
|
||||||
clang-format -i src/V3Begin.cpp
|
|
||||||
clang-format -i src/V3Branch.cpp
|
|
||||||
clang-format -i src/V3Broken.cpp
|
|
||||||
clang-format -i src/V3CCtors.cpp
|
|
||||||
clang-format -i src/V3Case.cpp
|
|
||||||
clang-format -i src/V3Cast.cpp
|
|
||||||
clang-format -i src/V3Cdc.cpp
|
|
||||||
clang-format -i src/V3Changed.cpp
|
|
||||||
clang-format -i src/V3Clean.cpp
|
|
||||||
clang-format -i src/V3Clock.cpp
|
|
||||||
clang-format -i src/V3Combine.cpp
|
|
||||||
clang-format -i src/V3Const.cpp
|
|
||||||
clang-format -i src/V3Coverage.cpp
|
|
||||||
clang-format -i src/V3CoverageJoin.cpp
|
|
||||||
clang-format -i src/V3Dead.cpp
|
|
||||||
clang-format -i src/V3Delayed.cpp
|
|
||||||
clang-format -i src/V3Depth.cpp
|
|
||||||
clang-format -i src/V3DepthBlock.cpp
|
|
||||||
clang-format -i src/V3EmitC.cpp
|
|
||||||
clang-format -i src/V3EmitCInlines.cpp
|
|
||||||
clang-format -i src/V3EmitCMake.cpp
|
|
||||||
clang-format -i src/V3EmitCSyms.cpp
|
|
||||||
clang-format -i src/V3EmitMk.cpp
|
|
||||||
clang-format -i src/V3EmitV.cpp
|
|
||||||
clang-format -i src/V3EmitXml.cpp
|
|
||||||
clang-format -i src/V3Error.cpp
|
|
||||||
clang-format -i src/V3Expand.cpp
|
|
||||||
clang-format -i src/V3File.cpp
|
|
||||||
clang-format -i src/V3FileLine.cpp
|
|
||||||
clang-format -i src/V3Gate.cpp
|
|
||||||
clang-format -i src/V3GenClk.cpp
|
|
||||||
clang-format -i src/V3Graph.cpp
|
|
||||||
clang-format -i src/V3GraphAcyc.cpp
|
|
||||||
clang-format -i src/V3GraphAlg.cpp
|
|
||||||
clang-format -i src/V3GraphDfa.cpp
|
|
||||||
clang-format -i src/V3GraphPathChecker.cpp
|
|
||||||
clang-format -i src/V3GraphTest.cpp
|
|
||||||
clang-format -i src/V3Hashed.cpp
|
|
||||||
clang-format -i src/V3Inline.cpp
|
|
||||||
clang-format -i src/V3Inst.cpp
|
|
||||||
clang-format -i src/V3InstrCount.cpp
|
|
||||||
clang-format -i src/V3Life.cpp
|
|
||||||
clang-format -i src/V3LifePost.cpp
|
|
||||||
clang-format -i src/V3LinkCells.cpp
|
|
||||||
clang-format -i src/V3LinkDot.cpp
|
|
||||||
clang-format -i src/V3LinkJump.cpp
|
|
||||||
clang-format -i src/V3LinkLValue.cpp
|
|
||||||
clang-format -i src/V3LinkLevel.cpp
|
|
||||||
clang-format -i src/V3LinkParse.cpp
|
|
||||||
clang-format -i src/V3LinkResolve.cpp
|
|
||||||
clang-format -i src/V3Localize.cpp
|
|
||||||
clang-format -i src/V3Name.cpp
|
|
||||||
clang-format -i src/V3Number.cpp
|
|
||||||
clang-format -i src/V3Number_test.cpp
|
|
||||||
clang-format -i src/V3Options.cpp
|
|
||||||
clang-format -i src/V3Order.cpp
|
|
||||||
clang-format -i src/V3Os.cpp
|
|
||||||
clang-format -i src/V3Param.cpp
|
|
||||||
clang-format -i src/V3ParseGrammar.cpp
|
|
||||||
clang-format -i src/V3ParseImp.cpp
|
|
||||||
clang-format -i src/V3ParseLex.cpp
|
|
||||||
clang-format -i src/V3Partition.cpp
|
|
||||||
clang-format -i src/V3PreProc.cpp
|
|
||||||
clang-format -i src/V3PreShell.cpp
|
|
||||||
clang-format -i src/V3Premit.cpp
|
|
||||||
clang-format -i src/V3ProtectLib.cpp
|
|
||||||
clang-format -i src/V3Reloop.cpp
|
|
||||||
clang-format -i src/V3Scope.cpp
|
|
||||||
clang-format -i src/V3Scoreboard.cpp
|
|
||||||
clang-format -i src/V3Slice.cpp
|
|
||||||
clang-format -i src/V3Split.cpp
|
|
||||||
clang-format -i src/V3SplitAs.cpp
|
|
||||||
clang-format -i src/V3SplitVar.cpp
|
|
||||||
clang-format -i src/V3Stats.cpp
|
|
||||||
clang-format -i src/V3StatsReport.cpp
|
|
||||||
clang-format -i src/V3String.cpp
|
|
||||||
clang-format -i src/V3Subst.cpp
|
|
||||||
clang-format -i src/V3TSP.cpp
|
|
||||||
clang-format -i src/V3Table.cpp
|
|
||||||
clang-format -i src/V3Task.cpp
|
|
||||||
clang-format -i src/V3Trace.cpp
|
|
||||||
clang-format -i src/V3TraceDecl.cpp
|
|
||||||
clang-format -i src/V3Tristate.cpp
|
|
||||||
clang-format -i src/V3Undriven.cpp
|
|
||||||
clang-format -i src/V3Unknown.cpp
|
|
||||||
clang-format -i src/V3Unroll.cpp
|
|
||||||
clang-format -i src/V3Width.cpp
|
|
||||||
clang-format -i src/V3WidthSel.cpp
|
|
||||||
clang-format -i src/Verilator.cpp
|
|
||||||
+18
-19
@@ -78,27 +78,27 @@ MSVC++.
|
|||||||
|
|
||||||
=== Install Prerequisites
|
=== Install Prerequisites
|
||||||
|
|
||||||
To build Verilator you will need to install some standard packages:
|
To build or run Verilator you need these standard packages:
|
||||||
|
|
||||||
sudo apt-get install git
|
sudo apt-get install perl python3 make
|
||||||
sudo apt-get install autoconf
|
|
||||||
sudo apt-get install flex bison
|
|
||||||
|
|
||||||
The following are optional, but improve compilation speed:
|
|
||||||
|
|
||||||
sudo apt-get install libgoogle-perftools-dev
|
|
||||||
|
|
||||||
Additionally, to build or run Verilator you need these standard packages:
|
|
||||||
|
|
||||||
sudo apt-get install perl python3
|
|
||||||
sudo apt-get install make
|
|
||||||
sudo apt-get install 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)
|
||||||
|
|
||||||
Those developing Verilator may also want these (see internals.adoc):
|
To build or run the following are optional but should be installed for
|
||||||
|
good performance:
|
||||||
|
|
||||||
sudo apt-get install gdb asciidoctor graphviz cmake
|
sudo apt-get install ccache # If present at build, needed for run
|
||||||
|
sudo apt-get install libgoogle-perftools-dev numactl
|
||||||
|
|
||||||
|
To build Verilator you will need to install these packages; these do not
|
||||||
|
need to be present to run Verilator:
|
||||||
|
|
||||||
|
sudo apt-get install git autoconf flex bison
|
||||||
|
|
||||||
|
Those developing Verilator itself may also want these (see internals.adoc):
|
||||||
|
|
||||||
|
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
|
||||||
@@ -264,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
|
||||||
|
|
||||||
|
|||||||
+38
-13
@@ -405,6 +405,15 @@ This sets indentation to the `cc-mode` defaults. (Verilator predates a
|
|||||||
CC-mode change of several years ago which overrides the defaults with GNU
|
CC-mode change of several years ago which overrides the defaults with GNU
|
||||||
style indentation; the `c-set-style` undoes that.)
|
style indentation; the `c-set-style` undoes that.)
|
||||||
|
|
||||||
|
* Use "mixedCapsSymbols" instead of "underlined_symbols".
|
||||||
|
|
||||||
|
* Uas a "p" suffix on variables that are pointers, e.g. "nodep".
|
||||||
|
|
||||||
|
* Comment every member variable.
|
||||||
|
|
||||||
|
Indentation is automatically maintained with "make clang-format" (using
|
||||||
|
clang-format version 10.0.0). For those manually formatting:
|
||||||
|
|
||||||
* Use 4 spaces per level, and no tabs.
|
* Use 4 spaces per level, and no tabs.
|
||||||
|
|
||||||
* Use 2 spaces between the end of source and the beginning of a comment.
|
* Use 2 spaces between the end of source and the beginning of a comment.
|
||||||
@@ -414,12 +423,6 @@ style indentation; the `c-set-style` undoes that.)
|
|||||||
* No spaces before semicolons, nor between a function's name and open
|
* No spaces before semicolons, nor between a function's name and open
|
||||||
parenthesis (only applies to functions; if/else has a following space).
|
parenthesis (only applies to functions; if/else has a following space).
|
||||||
|
|
||||||
* Use "mixedCapsSymbols" instead of "underlined_symbols".
|
|
||||||
|
|
||||||
* Uas a "p" suffix on variables that are pointers, e.g. "nodep".
|
|
||||||
|
|
||||||
* Comment every member variable.
|
|
||||||
|
|
||||||
=== The `astgen` Script
|
=== The `astgen` Script
|
||||||
|
|
||||||
Some of the code implementing passes is extremely repetitive, and must be
|
Some of the code implementing passes is extremely repetitive, and must be
|
||||||
@@ -783,10 +786,10 @@ better viewers let us know; ZGRViewer isn't great for large graphs.
|
|||||||
Tree files are dumps of the AST Tree and are produced between every major
|
Tree files are dumps of the AST Tree and are produced between every major
|
||||||
algorithmic stage. An example:
|
algorithmic stage. An example:
|
||||||
|
|
||||||
NETLIST 0x90fb00 <e1> {a0}
|
NETLIST 0x90fb00 <e1> {a0ah}
|
||||||
1: MODULE 0x912b20 <e8822> {a8} top L2 [P]
|
1: MODULE 0x912b20 <e8822> {a8ah} top L2 [P]
|
||||||
*1:2: VAR 0x91a780 <e74#> {a22} @dt=0xa2e640(w32) out_wide [O] WIRE
|
*1:2: VAR 0x91a780 <e74#> {a22ah} @dt=0xa2e640(w32) out_wide [O] WIRE
|
||||||
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24} @dt=this(sw32) integer kwd=integer range=[31:0]
|
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24ah} @dt=this(sw32) integer kwd=integer range=[31:0]
|
||||||
|
|
||||||
The following summarizes the above example dump, with more detail on each
|
The following summarizes the above example dump, with more detail on each
|
||||||
field in the section below.
|
field in the section below.
|
||||||
@@ -804,8 +807,9 @@ the `MODULE`, which in turn is the `op1p` pointer under the `NETLIST`
|
|||||||
| `<e74>` | means the 74th edit to the netlist was the last modification to
|
| `<e74>` | means the 74th edit to the netlist was the last modification to
|
||||||
this node.
|
this node.
|
||||||
|
|
||||||
| `{a22}` | indicates this node is related to line 22 in the source filename
|
| `{a22ah}` | indicates this node is related to the source filename "a",
|
||||||
"a", where "a" is the first file read, "z" the 26th, and "aa" the 27th.
|
where "a" is the first file read, "z" the 26th, and "aa" the 27th. Then
|
||||||
|
line 22 in that file, then column 8 (aa=0, az=25, ba=26, ...).
|
||||||
|
|
||||||
| `@dt=0x...` | indicates the address of the data type this node contains.
|
| `@dt=0x...` | indicates the address of the data type this node contains.
|
||||||
|
|
||||||
@@ -846,7 +850,10 @@ correspond directly to Verilog entities (for example `MODULE` and
|
|||||||
Address of the node::
|
Address of the node::
|
||||||
|
|
||||||
A hexadecimal address of the node in memory. Useful for examining with the
|
A hexadecimal address of the node in memory. Useful for examining with the
|
||||||
debugger.
|
debugger. If the actual address values are not important, then using the
|
||||||
|
`--dump-tree-addrids` option will convert address values to short identifiers
|
||||||
|
of the form `([A-Z]*)`, which is hopefully easier for the reader to cross
|
||||||
|
reference throughout the dump.
|
||||||
|
|
||||||
Last edit number::
|
Last edit number::
|
||||||
|
|
||||||
@@ -993,6 +1000,24 @@ function in `src/verilator.cpp`.
|
|||||||
To get your pass to build you'll need to add its binary filename to the
|
To get your pass to build you'll need to add its binary filename to the
|
||||||
list in `src/Makefile_obj.in` and reconfigure.
|
list in `src/Makefile_obj.in` and reconfigure.
|
||||||
|
|
||||||
|
=== "Never" features
|
||||||
|
|
||||||
|
Verilator ideally would support all of IEEE, and has the goal to get close
|
||||||
|
to full support. However the following IEEE sections and features are not
|
||||||
|
anticipated to be ever implemented for the reasons indicated.
|
||||||
|
|
||||||
|
[horizontal]
|
||||||
|
IEEE 1800-2017 3.3 recursive modules:: Little/no tool support, and arguably not a good practice.
|
||||||
|
IEEE 1800-2017 6.12 "shortreal":: Little/no tool support, and easily simply promoted to real.
|
||||||
|
IEEE 1800-2017 11.11 Min, typ, max:: No SDF support so will always use typical.
|
||||||
|
IEEE 1800-2017 11.12 "let":: Little/no tool support, makes difficult to implement parsers.
|
||||||
|
IEEE 1800-2017 20.15 Probabilistic functions:: Little industry use.
|
||||||
|
IEEE 1800-2017 20.16 Stochastic analysis:: Little industry use.
|
||||||
|
IEEE 1800-2017 20.17 PLA modeling:: Little industry use and outdated technology.
|
||||||
|
IEEE 1800-2017 31 Timing checks:: No longer relevant with static timing analysis tools.
|
||||||
|
IEEE 1800-2017 32 SDF annotation:: No longer relevant with static timing analysis tools.
|
||||||
|
IEEE 1800-2017 33 Config:: Little/no tool support or industry use.
|
||||||
|
|
||||||
== Distribution
|
== Distribution
|
||||||
|
|
||||||
Copyright 2008-2020 by Wilson Snyder. Verilator is free software; you can
|
Copyright 2008-2020 by Wilson Snyder. Verilator is free software; you can
|
||||||
|
|||||||
+1
-1
@@ -21,7 +21,7 @@ parser.
|
|||||||
|
|
||||||
== Structure
|
== Structure
|
||||||
|
|
||||||
The XML document is consists of 4 sections within the top level `verilator_xml`
|
The XML document consists of 4 sections within the top level `verilator_xml`
|
||||||
element:
|
element:
|
||||||
|
|
||||||
`<files>`...`</files>`::
|
`<files>`...`</files>`::
|
||||||
|
|||||||
@@ -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
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
@@ -51,11 +49,11 @@ run:
|
|||||||
@echo "-- Verilator CMake hello world example"
|
@echo "-- Verilator CMake hello world example"
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- CMake ----------------"
|
@echo "-- VERILATE ----------------"
|
||||||
mkdir -p build && cd build && cmake ..
|
mkdir -p build && cd build && cmake ..
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- COMPILE -----------------"
|
@echo "-- BUILD -------------------"
|
||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
|
|||||||
@@ -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
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
@@ -87,11 +85,11 @@ run:
|
|||||||
@echo "-- Verilator CMake SystemC hello-world simple example"
|
@echo "-- Verilator CMake SystemC hello-world simple example"
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- CMake ----------------"
|
@echo "-- VERILATE ----------------"
|
||||||
mkdir -p build && cd build && cmake ..
|
mkdir -p build && cd build && cmake ..
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- COMPILE -----------------"
|
@echo "-- BUILD -------------------"
|
||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
|
|||||||
@@ -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
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
@@ -51,11 +49,11 @@ run:
|
|||||||
@echo "-- Verilator CMake protect_lib example"
|
@echo "-- Verilator CMake protect_lib example"
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- CMake ----------------"
|
@echo "-- VERILATE ----------------"
|
||||||
mkdir -p build && cd build && cmake ..
|
mkdir -p build && cd build && cmake ..
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- COMPILE -----------------"
|
@echo "-- BUILD -------------------"
|
||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
|
|||||||
@@ -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
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
@@ -51,11 +49,11 @@ run:
|
|||||||
@echo "-- Verilator CMake tracing example"
|
@echo "-- Verilator CMake tracing example"
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- CMake ----------------"
|
@echo "-- VERILATE ----------------"
|
||||||
mkdir -p build && cd build && cmake ..
|
mkdir -p build && cd build && cmake ..
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- COMPILE -----------------"
|
@echo "-- BUILD -------------------"
|
||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
|
|||||||
@@ -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
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
@@ -87,11 +85,11 @@ run:
|
|||||||
@echo "-- Verilator CMake SystemC tracing example"
|
@echo "-- Verilator CMake SystemC tracing example"
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- CMake ----------------"
|
@echo "-- VERILATE ----------------"
|
||||||
mkdir -p build && cd build && cmake ..
|
mkdir -p build && cd build && cmake ..
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- COMPILE -----------------"
|
@echo "-- BUILD -------------------"
|
||||||
cmake --build build
|
cmake --build build
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -36,10 +34,8 @@ endif
|
|||||||
|
|
||||||
default:
|
default:
|
||||||
@echo "-- Verilator hello-world simple example"
|
@echo "-- Verilator hello-world simple example"
|
||||||
@echo "-- VERILATE ----------------"
|
@echo "-- VERILATE & BUILD --------"
|
||||||
$(VERILATOR) -cc --exe top.v sim_main.cpp
|
$(VERILATOR) -cc --exe --build -j top.v sim_main.cpp
|
||||||
@echo "-- COMPILE -----------------"
|
|
||||||
$(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
|
||||||
@echo "-- RUN ---------------------"
|
@echo "-- RUN ---------------------"
|
||||||
obj_dir/Vtop
|
obj_dir/Vtop
|
||||||
@echo "-- DONE --------------------"
|
@echo "-- DONE --------------------"
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -45,10 +43,8 @@ endif
|
|||||||
|
|
||||||
run:
|
run:
|
||||||
@echo "-- Verilator hello-world simple example"
|
@echo "-- Verilator hello-world simple example"
|
||||||
@echo "-- VERILATE ----------------"
|
@echo "-- VERILATE & COMPILE ------"
|
||||||
$(VERILATOR) -sc --exe top.v sc_main.cpp
|
$(VERILATOR) -sc --exe --build -j top.v sc_main.cpp
|
||||||
@echo "-- COMPILE -----------------"
|
|
||||||
$(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
|
||||||
@echo "-- RUN ---------------------"
|
@echo "-- RUN ---------------------"
|
||||||
obj_dir/Vtop
|
obj_dir/Vtop
|
||||||
@echo "-- DONE --------------------"
|
@echo "-- DONE --------------------"
|
||||||
|
|||||||
@@ -23,22 +23,22 @@ 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");
|
||||||
|
|
||||||
// Initialize SC model
|
// Initialize SC model
|
||||||
#if (SYSTEMC_VERSION>=20070314)
|
#if (SYSTEMC_VERSION >= 20070314)
|
||||||
sc_start(1,SC_NS);
|
sc_start(1, SC_NS);
|
||||||
#else
|
#else
|
||||||
sc_start(1);
|
sc_start(1);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Simulate until $finish
|
// Simulate until $finish
|
||||||
while (!Verilated::gotFinish()) {
|
while (!Verilated::gotFinish()) {
|
||||||
#if (SYSTEMC_VERSION>=20070314)
|
#if (SYSTEMC_VERSION >= 20070314)
|
||||||
sc_start(1,SC_NS);
|
sc_start(1, SC_NS);
|
||||||
#else
|
#else
|
||||||
sc_start(1);
|
sc_start(1);
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -6,14 +6,16 @@
|
|||||||
|
|
||||||
// This module will be used as libsecret.a or libsecret.so without
|
// This module will be used as libsecret.a or libsecret.so without
|
||||||
// exposing the source.
|
// exposing the source.
|
||||||
module secret_impl(
|
|
||||||
input [31:0] a,
|
|
||||||
input [31:0] b,
|
|
||||||
output logic [31:0] x,
|
|
||||||
input clk);
|
|
||||||
|
|
||||||
logic [31:0] accum_q = 0;
|
module secret_impl
|
||||||
logic [31:0] secret_value = 9;
|
(
|
||||||
|
input [31:0] a,
|
||||||
|
input [31:0] b,
|
||||||
|
output logic [31:0] x,
|
||||||
|
input clk);
|
||||||
|
|
||||||
|
logic [31:0] accum_q = 0;
|
||||||
|
logic [31:0] secret_value = 9;
|
||||||
|
|
||||||
initial $display("%m: initialized");
|
initial $display("%m: initialized");
|
||||||
|
|
||||||
|
|||||||
@@ -17,12 +17,10 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
vluint64_t main_time = 0;
|
vluint64_t main_time = 0;
|
||||||
double sc_time_stamp() {
|
double sc_time_stamp() { return main_time; }
|
||||||
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);
|
||||||
@@ -35,7 +33,7 @@ int main(int argc, char** argv, char** env) {
|
|||||||
// When tracing, the contents of the secret module will not be seen
|
// When tracing, the contents of the secret module will not be seen
|
||||||
VerilatedVcdC* tfp = NULL;
|
VerilatedVcdC* tfp = NULL;
|
||||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||||
if (flag && 0==strcmp(flag, "+trace")) {
|
if (flag && 0 == strcmp(flag, "+trace")) {
|
||||||
Verilated::traceEverOn(true);
|
Verilated::traceEverOn(true);
|
||||||
VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
|
VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
|
||||||
tfp = new VerilatedVcdC;
|
tfp = new VerilatedVcdC;
|
||||||
@@ -62,11 +60,15 @@ int main(int argc, char** argv, char** env) {
|
|||||||
|
|
||||||
// Close trace if opened
|
// Close trace if opened
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) { tfp->close(); tfp = NULL; }
|
if (tfp) {
|
||||||
|
tfp->close();
|
||||||
|
tfp = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Destroy model
|
// Destroy model
|
||||||
delete top; top = NULL;
|
delete top;
|
||||||
|
top = NULL;
|
||||||
|
|
||||||
// Fin
|
// Fin
|
||||||
exit(0);
|
exit(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
|
||||||
@@ -68,11 +66,13 @@ run:
|
|||||||
$(VERILATOR) $(VERILATOR_FLAGS) $(VERILATOR_INPUT)
|
$(VERILATOR) $(VERILATOR_FLAGS) $(VERILATOR_INPUT)
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- COMPILE -----------------"
|
@echo "-- BUILD -------------------"
|
||||||
# To compile, we can either just do what Verilator asks,
|
# To compile, we can either
|
||||||
# or call a submakefile where we can override the rules ourselves
|
# 1. Pass --build to Verilator by editing VERILATOR_FLAGS above.
|
||||||
# $(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
# 2. Or, run the make rules Verilator does:
|
||||||
$(MAKE) -j 4 -C obj_dir -f ../Makefile_obj
|
# $(MAKE) -j -C obj_dir -f Vtop.mk
|
||||||
|
# 3. Or, call a submakefile where we can override the rules ourselves:
|
||||||
|
$(MAKE) -j -C obj_dir -f ../Makefile_obj
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- RUN ---------------------"
|
@echo "-- RUN ---------------------"
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -83,9 +83,9 @@ int main(int argc, char** argv, char** env) {
|
|||||||
|
|
||||||
// Read outputs
|
// Read outputs
|
||||||
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
|
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
|
||||||
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
|
" -> oquad=%" VL_PRI64 "x owide=%x_%08x_%08x\n",
|
||||||
main_time, top->clk, top->reset_l, top->in_quad,
|
main_time, top->clk, top->reset_l, top->in_quad, top->out_quad, top->out_wide[2],
|
||||||
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
|
top->out_wide[1], top->out_wide[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final model cleanup
|
// Final model cleanup
|
||||||
@@ -98,7 +98,8 @@ int main(int argc, char** argv, char** env) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Destroy model
|
// Destroy model
|
||||||
delete top; top = NULL;
|
delete top;
|
||||||
|
top = NULL;
|
||||||
|
|
||||||
// Fin
|
// Fin
|
||||||
exit(0);
|
exit(0);
|
||||||
|
|||||||
@@ -11,15 +11,15 @@
|
|||||||
module top
|
module top
|
||||||
(
|
(
|
||||||
// Declare some signals so we can see how I/O works
|
// Declare some signals so we can see how I/O works
|
||||||
input clk,
|
input clk,
|
||||||
input reset_l,
|
input reset_l,
|
||||||
|
|
||||||
output wire [1:0] out_small,
|
output wire [1:0] out_small,
|
||||||
output wire [39:0] out_quad,
|
output wire [39:0] out_quad,
|
||||||
output wire [69:0] out_wide,
|
output wire [69:0] out_wide,
|
||||||
input [1:0] in_small,
|
input [1:0] in_small,
|
||||||
input [39:0] in_quad,
|
input [39:0] in_quad,
|
||||||
input [69:0] in_wide
|
input [69:0] in_wide
|
||||||
);
|
);
|
||||||
|
|
||||||
// Connect up the outputs, using some trivial logic
|
// Connect up the outputs, using some trivial logic
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -77,10 +75,12 @@ run:
|
|||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- COMPILE -----------------"
|
@echo "-- COMPILE -----------------"
|
||||||
# To compile, we can either just do what Verilator asks,
|
# To compile, we can either
|
||||||
# or call a submakefile where we can override the rules ourselves
|
# 1. Pass --build to Verilator by editing VERILATOR_FLAGS above.
|
||||||
# $(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
# 2. Or, run the make rules Verilator does:
|
||||||
$(MAKE) -j 4 -C obj_dir -f ../Makefile_obj
|
# $(MAKE) -j -C obj_dir -f Vtop.mk
|
||||||
|
# 3. Or, call a submakefile where we can override the rules ourselves:
|
||||||
|
$(MAKE) -j -C obj_dir -f ../Makefile_obj
|
||||||
|
|
||||||
@echo
|
@echo
|
||||||
@echo "-- RUN ---------------------"
|
@echo "-- RUN ---------------------"
|
||||||
|
|||||||
@@ -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
|
||||||
@@ -45,19 +45,19 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
ios::sync_with_stdio();
|
ios::sync_with_stdio();
|
||||||
|
|
||||||
// Defaults time
|
// Defaults time
|
||||||
#if (SYSTEMC_VERSION>20011000)
|
#if (SYSTEMC_VERSION > 20011000)
|
||||||
#else
|
#else
|
||||||
sc_time dut(1.0, sc_ns);
|
sc_time dut(1.0, sc_ns);
|
||||||
sc_set_default_time_unit(dut);
|
sc_set_default_time_unit(dut);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Define clocks
|
// Define clocks
|
||||||
#if (SYSTEMC_VERSION>=20070314)
|
#if (SYSTEMC_VERSION >= 20070314)
|
||||||
sc_clock clk ("clk", 10,SC_NS, 0.5, 3,SC_NS, true);
|
sc_clock clk("clk", 10, SC_NS, 0.5, 3, SC_NS, true);
|
||||||
sc_clock fastclk ("fastclk", 2,SC_NS, 0.5, 2,SC_NS, true);
|
sc_clock fastclk("fastclk", 2, SC_NS, 0.5, 2, SC_NS, true);
|
||||||
#else
|
#else
|
||||||
sc_clock clk ("clk", 10, 0.5, 3, true);
|
sc_clock clk("clk", 10, 0.5, 3, true);
|
||||||
sc_clock fastclk ("fastclk", 2, 0.5, 2, true);
|
sc_clock fastclk("fastclk", 2, 0.5, 2, true);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Define interconnect
|
// Define interconnect
|
||||||
@@ -72,15 +72,15 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
// Construct the Verilated model, from inside Vtop.h
|
// Construct the Verilated model, from inside Vtop.h
|
||||||
Vtop* top = new Vtop("top");
|
Vtop* top = new Vtop("top");
|
||||||
// Attach signals to the model
|
// Attach signals to the model
|
||||||
top->clk (clk);
|
top->clk(clk);
|
||||||
top->fastclk (fastclk);
|
top->fastclk(fastclk);
|
||||||
top->reset_l (reset_l);
|
top->reset_l(reset_l);
|
||||||
top->in_small (in_small);
|
top->in_small(in_small);
|
||||||
top->in_quad (in_quad);
|
top->in_quad(in_quad);
|
||||||
top->in_wide (in_wide);
|
top->in_wide(in_wide);
|
||||||
top->out_small (out_small);
|
top->out_small(out_small);
|
||||||
top->out_quad (out_quad);
|
top->out_quad(out_quad);
|
||||||
top->out_wide (out_wide);
|
top->out_wide(out_wide);
|
||||||
|
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
// Before any evaluation, need to know to calculate those signals only used for tracing
|
// Before any evaluation, need to know to calculate those signals only used for tracing
|
||||||
@@ -89,8 +89,8 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// You must do one evaluation before enabling waves, in order to allow
|
// You must do one evaluation before enabling waves, in order to allow
|
||||||
// SystemC to interconnect everything for testing.
|
// SystemC to interconnect everything for testing.
|
||||||
#if (SYSTEMC_VERSION>=20070314)
|
#if (SYSTEMC_VERSION >= 20070314)
|
||||||
sc_start(1,SC_NS);
|
sc_start(1, SC_NS);
|
||||||
#else
|
#else
|
||||||
sc_start(1);
|
sc_start(1);
|
||||||
#endif
|
#endif
|
||||||
@@ -100,7 +100,7 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
// and if at run time passed the +trace argument, turn on tracing
|
// and if at run time passed the +trace argument, turn on tracing
|
||||||
VerilatedVcdSc* tfp = NULL;
|
VerilatedVcdSc* tfp = NULL;
|
||||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||||
if (flag && 0==strcmp(flag, "+trace")) {
|
if (flag && 0 == strcmp(flag, "+trace")) {
|
||||||
cout << "Enabling waves into logs/vlt_dump.vcd...\n";
|
cout << "Enabling waves into logs/vlt_dump.vcd...\n";
|
||||||
tfp = new VerilatedVcdSc;
|
tfp = new VerilatedVcdSc;
|
||||||
top->trace(tfp, 99); // Trace 99 levels of hierarchy
|
top->trace(tfp, 99); // Trace 99 levels of hierarchy
|
||||||
@@ -118,15 +118,15 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Apply inputs
|
// Apply inputs
|
||||||
if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) {
|
if (sc_time_stamp() > sc_time(1, SC_NS) && sc_time_stamp() < sc_time(10, SC_NS)) {
|
||||||
reset_l = !1; // Assert reset
|
reset_l = !1; // Assert reset
|
||||||
} else if (VL_TIME_Q() > 1) {
|
} else {
|
||||||
reset_l = !0; // Deassert reset
|
reset_l = !0; // Deassert reset
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simulate 1ns
|
// Simulate 1ns
|
||||||
#if (SYSTEMC_VERSION>=20070314)
|
#if (SYSTEMC_VERSION >= 20070314)
|
||||||
sc_start(1,SC_NS);
|
sc_start(1, SC_NS);
|
||||||
#else
|
#else
|
||||||
sc_start(1);
|
sc_start(1);
|
||||||
#endif
|
#endif
|
||||||
@@ -137,7 +137,10 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
|
|
||||||
// Close trace if opened
|
// Close trace if opened
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) { tfp->close(); tfp = NULL; }
|
if (tfp) {
|
||||||
|
tfp->close();
|
||||||
|
tfp = NULL;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Coverage analysis (since test passed)
|
// Coverage analysis (since test passed)
|
||||||
@@ -147,7 +150,8 @@ int sc_main(int argc, char* argv[]) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Destroy model
|
// Destroy model
|
||||||
delete top; top = NULL;
|
delete top;
|
||||||
|
top = NULL;
|
||||||
|
|
||||||
// Fin
|
// Fin
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -11,16 +11,16 @@
|
|||||||
module top
|
module top
|
||||||
(
|
(
|
||||||
// Declare some signals so we can see how I/O works
|
// Declare some signals so we can see how I/O works
|
||||||
input clk,
|
input clk,
|
||||||
input fastclk,
|
input fastclk,
|
||||||
input reset_l,
|
input reset_l,
|
||||||
|
|
||||||
output wire [1:0] out_small,
|
output wire [1:0] out_small,
|
||||||
output wire [39:0] out_quad,
|
output wire [39:0] out_quad,
|
||||||
output wire [69:0] out_wide,
|
output wire [69:0] out_wide,
|
||||||
input [1:0] in_small,
|
input [1:0] in_small,
|
||||||
input [39:0] in_quad,
|
input [39:0] in_quad,
|
||||||
input [69:0] in_wide
|
input [69:0] in_wide
|
||||||
);
|
);
|
||||||
|
|
||||||
// Connect up the outputs, using some trivial logic
|
// Connect up the outputs, using some trivial logic
|
||||||
|
|||||||
@@ -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
|
|
||||||
#
|
#
|
||||||
######################################################################
|
######################################################################
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
module sub
|
module sub
|
||||||
#(parameter type TYPE_t = logic)
|
#(parameter type TYPE_t = logic)
|
||||||
(
|
(
|
||||||
input TYPE_t in,
|
input TYPE_t in,
|
||||||
output TYPE_t out
|
output TYPE_t out
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -7,16 +7,16 @@
|
|||||||
|
|
||||||
module top
|
module top
|
||||||
(
|
(
|
||||||
input clk,
|
input clk,
|
||||||
input fastclk,
|
input fastclk,
|
||||||
input reset_l,
|
input reset_l,
|
||||||
|
|
||||||
output wire [1:0] out_small,
|
output wire [1:0] out_small,
|
||||||
output wire [39:0] out_quad,
|
output wire [39:0] out_quad,
|
||||||
output wire [69:0] out_wide,
|
output wire [69:0] out_wide,
|
||||||
input [1:0] in_small,
|
input [1:0] in_small,
|
||||||
input [39:0] in_quad,
|
input [39:0] in_quad,
|
||||||
input [69:0] in_wide
|
input [69:0] in_wide
|
||||||
);
|
);
|
||||||
|
|
||||||
sub #(.TYPE_t(logic [1:0])) sub_small
|
sub #(.TYPE_t(logic [1:0])) sub_small
|
||||||
|
|||||||
+739
-542
File diff suppressed because it is too large
Load Diff
+779
-622
File diff suppressed because it is too large
Load Diff
+73
-48
@@ -12,8 +12,9 @@
|
|||||||
PERL = @PERL@
|
PERL = @PERL@
|
||||||
CXX = @CXX@
|
CXX = @CXX@
|
||||||
LINK = @CXX@
|
LINK = @CXX@
|
||||||
AR = ar
|
AR = ar
|
||||||
RANLIB = ranlib
|
RANLIB = ranlib
|
||||||
|
OBJCACHE ?= @OBJCACHE@
|
||||||
|
|
||||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||||
@@ -83,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
|
||||||
@@ -114,62 +117,87 @@ endif
|
|||||||
#######################################################################
|
#######################################################################
|
||||||
##### Threaded builds
|
##### Threaded builds
|
||||||
|
|
||||||
|
ifneq ($(VM_C11),0)
|
||||||
|
ifneq ($(VM_C11),)
|
||||||
|
VK_C11=1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(VM_THREADS),0)
|
ifneq ($(VM_THREADS),0)
|
||||||
ifneq ($(VM_THREADS),)
|
ifneq ($(VM_THREADS),)
|
||||||
CPPFLAGS += -DVL_THREADED
|
CPPFLAGS += -DVL_THREADED
|
||||||
|
VK_C11=1
|
||||||
VK_LIBS_THREADED=1
|
VK_LIBS_THREADED=1
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(VM_TRACE_THREADED),0)
|
ifneq ($(VM_TRACE_THREADS),0)
|
||||||
ifneq ($(VM_TRACE_THREADED),)
|
ifneq ($(VM_TRACE_THREADS),)
|
||||||
|
ifeq ($(findstring -DVL_THREADED,$(CPPFLAGS)),)
|
||||||
|
$(error VM_TRACE_THREADS requires VM_THREADS)
|
||||||
|
endif
|
||||||
CPPFLAGS += -DVL_TRACE_THREADED
|
CPPFLAGS += -DVL_TRACE_THREADED
|
||||||
|
VK_C11=1
|
||||||
VK_LIBS_THREADED=1
|
VK_LIBS_THREADED=1
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
ifneq ($(VM_TRACE_FST_WRITER_THREAD),0)
|
||||||
|
ifneq ($(VM_TRACE_FST_WRITER_THREAD),)
|
||||||
|
CPPFLAGS += -DVL_TRACE_FST_WRITER_THREAD
|
||||||
|
VK_C11=1
|
||||||
|
VK_LIBS_THREADED=1
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifneq ($(VK_C11),0)
|
||||||
|
ifneq ($(VK_C11),)
|
||||||
|
# Need C++11 at least, so always default to newest
|
||||||
|
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
ifneq ($(VK_LIBS_THREADED),0)
|
ifneq ($(VK_LIBS_THREADED),0)
|
||||||
ifneq ($(VK_LIBS_THREADED),)
|
ifneq ($(VK_LIBS_THREADED),)
|
||||||
# Need C++11 at least, so always default to newest
|
|
||||||
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
|
|
||||||
LDLIBS += $(CFG_LDLIBS_THREADS)
|
LDLIBS += $(CFG_LDLIBS_THREADS)
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
##### Stub
|
### Aggregates
|
||||||
|
|
||||||
preproc:
|
VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST)
|
||||||
|
VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
##### C/H builds
|
### Overall Objects Linking
|
||||||
|
|
||||||
LIBS += -lm -lstdc++
|
VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
|
||||||
|
VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
|
||||||
#######################################################################
|
|
||||||
# Overall Objects Linking
|
|
||||||
|
|
||||||
VK_CLASSES_H = $(addsuffix .h, $(VM_CLASSES))
|
|
||||||
VK_CLASSES_CPP = $(addsuffix .cpp, $(VM_CLASSES))
|
|
||||||
|
|
||||||
VK_SUPPORT_CPP = $(addsuffix .cpp, $(VM_SUPPORT))
|
|
||||||
|
|
||||||
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)__ALLcls.o $(VM_PREFIX)__ALLsup.o
|
# also a lot slower for medium to large designs when the speed of the C
|
||||||
all_cpp: $(VM_PREFIX)__ALLcls.cpp $(VM_PREFIX)__ALLsup.cpp
|
# compiler dominates, which in this mode is not parallelizable.
|
||||||
$(VM_PREFIX)__ALLcls.cpp: $(VK_CLASSES_CPP)
|
|
||||||
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
|
VK_OBJS += $(VM_PREFIX)__ALL.o
|
||||||
$(VM_PREFIX)__ALLsup.cpp: $(VK_SUPPORT_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)
|
||||||
@@ -180,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)__ALLcls.o: $(VM_PREFIX)__ALLcls.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)__ALLsup.o: $(VM_PREFIX)__ALLsup.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:
|
||||||
|
|||||||
@@ -16,9 +16,8 @@
|
|||||||
///
|
///
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
|
|
||||||
///**** Product and Version name
|
///**** Product and Version name
|
||||||
|
|
||||||
// Autoconf substitutes this with the strings from AC_INIT.
|
// Autoconf substitutes this with the strings from AC_INIT.
|
||||||
#define VERILATOR_PRODUCT "@PACKAGE_NAME@"
|
#define VERILATOR_PRODUCT "@PACKAGE_NAME@"
|
||||||
#define VERILATOR_VERSION "@PACKAGE_VERSION@"
|
#define VERILATOR_VERSION "@PACKAGE_VERSION@"
|
||||||
|
|||||||
+134
-118
@@ -47,7 +47,7 @@ public: // But only local to this file
|
|||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
// Derived classes should call zero() in their constructor
|
// Derived classes should call zero() in their constructor
|
||||||
VerilatedCovImpItem() {
|
VerilatedCovImpItem() {
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||||
m_keys[i] = KEY_UNDEF;
|
m_keys[i] = KEY_UNDEF;
|
||||||
m_vals[i] = 0;
|
m_vals[i] = 0;
|
||||||
}
|
}
|
||||||
@@ -66,7 +66,7 @@ public: // But only local to this file
|
|||||||
template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
|
template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
T* m_countp; ///< Count value
|
T* m_countp; ///< Count value
|
||||||
public:
|
public:
|
||||||
// METHODS
|
// METHODS
|
||||||
// cppcheck-suppress truncLongCastReturn
|
// cppcheck-suppress truncLongCastReturn
|
||||||
@@ -74,7 +74,10 @@ public:
|
|||||||
virtual void zero() const VL_OVERRIDE { *m_countp = 0; }
|
virtual void zero() const VL_OVERRIDE { *m_countp = 0; }
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
// cppcheck-suppress noExplicitConstructor
|
// cppcheck-suppress noExplicitConstructor
|
||||||
explicit VerilatedCoverItemSpec(T* countp) : m_countp(countp) { *m_countp = 0; }
|
explicit VerilatedCoverItemSpec(T* countp)
|
||||||
|
: m_countp(countp) {
|
||||||
|
*m_countp = 0;
|
||||||
|
}
|
||||||
virtual ~VerilatedCoverItemSpec() VL_OVERRIDE {}
|
virtual ~VerilatedCoverItemSpec() VL_OVERRIDE {}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -87,20 +90,19 @@ public:
|
|||||||
class VerilatedCovImp : VerilatedCovImpBase {
|
class VerilatedCovImp : VerilatedCovImpBase {
|
||||||
private:
|
private:
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef std::map<std::string,int> ValueIndexMap;
|
typedef std::map<std::string, int> ValueIndexMap;
|
||||||
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, when VL_THREADED. Wrapper deals with setting it.
|
VerilatedMutex m_mutex; ///< Protects all members
|
||||||
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values
|
||||||
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for keys
|
||||||
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
||||||
|
|
||||||
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex); ///< Item about to insert
|
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex); ///< Item about to insert
|
||||||
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex); ///< Filename about to insert
|
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex); ///< Filename about to insert
|
||||||
int m_insertLineno VL_GUARDED_BY(m_mutex); ///< Line number about to insert
|
int m_insertLineno VL_GUARDED_BY(m_mutex); ///< Line number about to insert
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedCovImp() {
|
VerilatedCovImp() {
|
||||||
@@ -109,6 +111,7 @@ private:
|
|||||||
m_insertLineno = 0;
|
m_insertLineno = 0;
|
||||||
}
|
}
|
||||||
VL_UNCOPYABLE(VerilatedCovImp);
|
VL_UNCOPYABLE(VerilatedCovImp);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~VerilatedCovImp() { clearGuts(); }
|
~VerilatedCovImp() { clearGuts(); }
|
||||||
static VerilatedCovImp& imp() VL_MT_SAFE {
|
static VerilatedCovImp& imp() VL_MT_SAFE {
|
||||||
@@ -119,10 +122,11 @@ public:
|
|||||||
private:
|
private:
|
||||||
// PRIVATE METHODS
|
// PRIVATE METHODS
|
||||||
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
||||||
static int nextIndex = KEY_UNDEF+1;
|
static int nextIndex = KEY_UNDEF + 1;
|
||||||
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
||||||
if (iter != m_valueIndexes.end()) return iter->second;
|
if (iter != m_valueIndexes.end()) return iter->second;
|
||||||
nextIndex++; assert(nextIndex>0);
|
nextIndex++;
|
||||||
|
assert(nextIndex > 0); // Didn't rollover
|
||||||
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
||||||
m_indexValues.insert(std::make_pair(nextIndex, value));
|
m_indexValues.insert(std::make_pair(nextIndex, value));
|
||||||
return nextIndex;
|
return nextIndex;
|
||||||
@@ -131,8 +135,9 @@ private:
|
|||||||
// Quote any special characters
|
// Quote any special characters
|
||||||
std::string rtn;
|
std::string rtn;
|
||||||
for (const char* pos = text.c_str(); *pos; ++pos) {
|
for (const char* pos = text.c_str(); *pos; ++pos) {
|
||||||
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
|
if (!isprint(*pos) || *pos == '%' || *pos == '"') {
|
||||||
char hex[10]; sprintf(hex, "%%%02X", pos[0]);
|
char hex[10];
|
||||||
|
sprintf(hex, "%%%02X", pos[0]);
|
||||||
rtn += hex;
|
rtn += hex;
|
||||||
} else {
|
} else {
|
||||||
rtn += *pos;
|
rtn += *pos;
|
||||||
@@ -145,18 +150,19 @@ private:
|
|||||||
// don't want applications to either get confused if they use
|
// don't want applications to either get confused if they use
|
||||||
// a letter differently, nor want them to rely on our compression...
|
// a letter differently, nor want them to rely on our compression...
|
||||||
// (Considered using numeric keys, but will remain back compatible.)
|
// (Considered using numeric keys, but will remain back compatible.)
|
||||||
if (key.length()<2) return false;
|
if (key.length() < 2) return false;
|
||||||
if (key.length()==2 && isdigit(key[1])) return false;
|
if (key.length() == 2 && isdigit(key[1])) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE {
|
static std::string keyValueFormatter(const std::string& key,
|
||||||
|
const std::string& value) VL_PURE {
|
||||||
std::string name;
|
std::string name;
|
||||||
if (key.length()==1 && isalpha(key[0])) {
|
if (key.length() == 1 && isalpha(key[0])) {
|
||||||
name += std::string("\001")+key;
|
name += std::string("\001") + key;
|
||||||
} else {
|
} else {
|
||||||
name += std::string("\001")+dequote(key);
|
name += std::string("\001") + dequote(key);
|
||||||
}
|
}
|
||||||
name += std::string("\002")+dequote(value);
|
name += std::string("\002") + dequote(value);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
|
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
|
||||||
@@ -173,28 +179,35 @@ private:
|
|||||||
// Scan forward to first mismatch
|
// Scan forward to first mismatch
|
||||||
const char* apre = a;
|
const char* apre = a;
|
||||||
const char* bpre = b;
|
const char* bpre = b;
|
||||||
while (*apre == *bpre) { apre++; bpre++; }
|
while (*apre == *bpre) {
|
||||||
|
apre++;
|
||||||
|
bpre++;
|
||||||
|
}
|
||||||
|
|
||||||
// We used to backup and split on only .'s but it seems better to be verbose
|
// We used to backup and split on only .'s but it seems better to be verbose
|
||||||
// and not assume . is the separator
|
// and not assume . is the separator
|
||||||
std::string prefix = std::string(a, apre-a);
|
std::string prefix = std::string(a, apre - a);
|
||||||
|
|
||||||
// Scan backward to last mismatch
|
// Scan backward to last mismatch
|
||||||
const char* apost = a+strlen(a)-1;
|
const char* apost = a + strlen(a) - 1;
|
||||||
const char* bpost = b+strlen(b)-1;
|
const char* bpost = b + strlen(b) - 1;
|
||||||
while (*apost == *bpost
|
while (*apost == *bpost && apost > apre && bpost > bpre) {
|
||||||
&& apost>apre && bpost>bpre) { apost--; bpost--; }
|
apost--;
|
||||||
|
bpost--;
|
||||||
|
}
|
||||||
|
|
||||||
// Forward to . so we have a whole word
|
// Forward to . so we have a whole word
|
||||||
std::string suffix = *bpost ? std::string(bpost+1) : "";
|
std::string suffix = *bpost ? std::string(bpost + 1) : "";
|
||||||
|
|
||||||
std::string out = prefix+"*"+suffix;
|
std::string out = prefix + "*" + suffix;
|
||||||
|
|
||||||
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
|
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
|
||||||
|
// <<"\ncho="<<out<<endl;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) VL_REQUIRES(m_mutex) {
|
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match)
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
VL_REQUIRES(m_mutex) {
|
||||||
|
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||||
// We don't compare keys, only values
|
// We don't compare keys, only values
|
||||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||||
@@ -207,17 +220,23 @@ private:
|
|||||||
}
|
}
|
||||||
static void selftest() VL_MT_SAFE {
|
static void selftest() VL_MT_SAFE {
|
||||||
// Little selftest
|
// Little selftest
|
||||||
if (combineHier("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
#define VL_CST_CHECK(got, exp) \
|
||||||
if (combineHier("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
do { \
|
||||||
if (combineHier("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest\n"); \
|
||||||
if (combineHier("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
} while (0)
|
||||||
if (combineHier("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
|
||||||
if (combineHier("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
VL_CST_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
|
||||||
if (combineHier("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
VL_CST_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
|
||||||
if (combineHier("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
VL_CST_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
|
||||||
|
VL_CST_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
|
||||||
|
VL_CST_CHECK(combineHier("z", "a"), "*");
|
||||||
|
VL_CST_CHECK(combineHier("q.a", "q.b"), "q.*");
|
||||||
|
VL_CST_CHECK(combineHier("q.za", "q.zb"), "q.z*");
|
||||||
|
VL_CST_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
|
||||||
|
#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) {
|
||||||
VerilatedCovImpItem* itemp = *(it);
|
VerilatedCovImpItem* itemp = *(it);
|
||||||
VL_DO_DANGLING(delete itemp, itemp);
|
VL_DO_DANGLING(delete itemp, itemp);
|
||||||
}
|
}
|
||||||
@@ -230,15 +249,15 @@ 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) {
|
||||||
VerilatedCovImpItem* itemp = *(it);
|
VerilatedCovImpItem* itemp = *(it);
|
||||||
if (!itemMatchesString(itemp, matchp)) {
|
if (!itemMatchesString(itemp, matchp)) {
|
||||||
VL_DO_DANGLING(delete itemp, itemp);
|
VL_DO_DANGLING(delete itemp, itemp);
|
||||||
@@ -251,50 +270,50 @@ 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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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],
|
void insertp(const char* ckeyps[MAX_KEYS], const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
||||||
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
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"; valps[0]=m_insertFilenamep;
|
ckeyps[0] = "filename";
|
||||||
|
valps[0] = m_insertFilenamep;
|
||||||
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
||||||
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
|
ckeyps[1] = "lineno";
|
||||||
|
valps[1] = linestr.c_str();
|
||||||
// Default page if not specified
|
// Default page if not specified
|
||||||
const char* fnstartp = m_insertFilenamep;
|
const char* fnstartp = m_insertFilenamep;
|
||||||
while (const char* foundp = strchr(fnstartp,'/')) fnstartp = foundp+1;
|
while (const char* foundp = strchr(fnstartp, '/')) fnstartp = foundp + 1;
|
||||||
const char* fnendp = fnstartp;
|
const char* fnendp = fnstartp;
|
||||||
while (*fnendp && *fnendp!='.') fnendp++;
|
for (; *fnendp && *fnendp != '.'; fnendp++) {}
|
||||||
std::string page_default = "sp_user/"+std::string(fnstartp, fnendp-fnstartp);
|
std::string page_default = "sp_user/" + std::string(fnstartp, fnendp - fnstartp);
|
||||||
ckeyps[2]="page"; valps[2]=page_default.c_str();
|
ckeyps[2] = "page";
|
||||||
|
valps[2] = page_default.c_str();
|
||||||
|
|
||||||
// Keys -> strings
|
// Keys -> strings
|
||||||
std::string keys[MAX_KEYS];
|
std::string keys[MAX_KEYS];
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||||
if (ckeyps[i] && ckeyps[i][0]) {
|
if (ckeyps[i] && ckeyps[i][0]) { keys[i] = ckeyps[i]; }
|
||||||
keys[i] = ckeyps[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Ignore empty keys
|
// Ignore empty keys
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||||
if (!keys[i].empty()) {
|
if (!keys[i].empty()) {
|
||||||
for (int j=i+1; j<MAX_KEYS; ++j) {
|
for (int j = i + 1; j < MAX_KEYS; ++j) {
|
||||||
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
|
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
|
||||||
keys[i] = "";
|
keys[i] = "";
|
||||||
break;
|
break;
|
||||||
@@ -304,18 +323,18 @@ public:
|
|||||||
}
|
}
|
||||||
// Insert the values
|
// Insert the values
|
||||||
int addKeynum = 0;
|
int addKeynum = 0;
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||||
const std::string key = keys[i];
|
const std::string key = keys[i];
|
||||||
if (!keys[i].empty()) {
|
if (!keys[i].empty()) {
|
||||||
const std::string val = valps[i];
|
const std::string val = valps[i];
|
||||||
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
// cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
||||||
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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -327,7 +346,7 @@ public:
|
|||||||
|
|
||||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||||
Verilated::quiesce();
|
Verilated::quiesce();
|
||||||
VerilatedLockGuard lock(m_mutex);
|
const VerilatedLockGuard lock(m_mutex);
|
||||||
#ifndef VM_COVERAGE
|
#ifndef VM_COVERAGE
|
||||||
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||||
#endif
|
#endif
|
||||||
@@ -335,22 +354,22 @@ public:
|
|||||||
|
|
||||||
std::ofstream os(filename);
|
std::ofstream os(filename);
|
||||||
if (os.fail()) {
|
if (os.fail()) {
|
||||||
std::string msg = std::string("%Error: Can't write '")+filename+"'";
|
std::string msg = std::string("%Error: Can't write '") + filename + "'";
|
||||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
os << "# SystemC::Coverage-3\n";
|
os << "# SystemC::Coverage-3\n";
|
||||||
|
|
||||||
// Build list of events; totalize if collapsing hierarchy
|
// Build list of events; totalize if collapsing hierarchy
|
||||||
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
|
typedef std::map<std::string, std::pair<std::string, vluint64_t> > EventMap;
|
||||||
EventMap eventCounts;
|
EventMap eventCounts;
|
||||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
for (ItemList::iterator it = m_items.begin(); it != m_items.end(); ++it) {
|
||||||
VerilatedCovImpItem* itemp = *(it);
|
VerilatedCovImpItem* itemp = *(it);
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string hier;
|
std::string hier;
|
||||||
bool per_instance = false;
|
bool per_instance = false;
|
||||||
|
|
||||||
for (int i=0; i<MAX_KEYS; ++i) {
|
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||||
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
||||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||||
@@ -380,19 +399,19 @@ public:
|
|||||||
if (cit != eventCounts.end()) {
|
if (cit != eventCounts.end()) {
|
||||||
const std::string& oldhier = cit->second.first;
|
const std::string& oldhier = cit->second.first;
|
||||||
cit->second.second += itemp->count();
|
cit->second.second += itemp->count();
|
||||||
cit->second.first = combineHier(oldhier, hier);
|
cit->second.first = combineHier(oldhier, hier);
|
||||||
} else {
|
} else {
|
||||||
eventCounts.insert(std::make_pair(name, make_pair(hier, itemp->count())));
|
eventCounts.insert(std::make_pair(name, make_pair(hier, itemp->count())));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output body
|
// Output body
|
||||||
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
for (EventMap::const_iterator it = eventCounts.begin(); it != eventCounts.end(); ++it) {
|
||||||
os<<"C '"<<std::dec;
|
os << "C '" << std::dec;
|
||||||
os<<it->first;
|
os << it->first;
|
||||||
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER, it->second.first);
|
if (!it->second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, it->second.first);
|
||||||
os<<"' "<<it->second.second;
|
os << "' " << it->second.second;
|
||||||
os<<std::endl;
|
os << std::endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -400,15 +419,11 @@ public:
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedCov
|
// VerilatedCov
|
||||||
|
|
||||||
void VerilatedCov::clear() VL_MT_SAFE {
|
void VerilatedCov::clear() VL_MT_SAFE { VerilatedCovImp::imp().clear(); }
|
||||||
VerilatedCovImp::imp().clear();
|
|
||||||
}
|
|
||||||
void VerilatedCov::clearNonMatch(const char* matchp) VL_MT_SAFE {
|
void VerilatedCov::clearNonMatch(const char* matchp) VL_MT_SAFE {
|
||||||
VerilatedCovImp::imp().clearNonMatch(matchp);
|
VerilatedCovImp::imp().clearNonMatch(matchp);
|
||||||
}
|
}
|
||||||
void VerilatedCov::zero() VL_MT_SAFE {
|
void VerilatedCov::zero() VL_MT_SAFE { VerilatedCovImp::imp().zero(); }
|
||||||
VerilatedCovImp::imp().zero();
|
|
||||||
}
|
|
||||||
void VerilatedCov::write(const char* filenamep) VL_MT_SAFE {
|
void VerilatedCov::write(const char* filenamep) VL_MT_SAFE {
|
||||||
VerilatedCovImp::imp().write(filenamep);
|
VerilatedCovImp::imp().write(filenamep);
|
||||||
}
|
}
|
||||||
@@ -422,48 +437,49 @@ void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE {
|
|||||||
VerilatedCovImp::imp().insertf(filename, lineno);
|
VerilatedCovImp::imp().insertf(filename, lineno);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define K(n) const char* key ## n
|
#define K(n) const char* key##n
|
||||||
#define A(n) const char* key ## n, const char* valp ## n // Argument list
|
#define A(n) const char *key##n, const char *valp##n // Argument list
|
||||||
#define C(n) key ## n, valp ## n // Calling argument list
|
#define C(n) key##n, valp##n // Calling argument list
|
||||||
#define N(n) "","" // Null argument list
|
#define N(n) "", "" // Null argument list
|
||||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10),
|
||||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19),
|
A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20),
|
||||||
A(20),A(21),A(22),A(23),A(24),A(25),A(26),A(27),A(28),A(29)) VL_MT_SAFE {
|
A(21), A(22), A(23), A(24), A(25), A(26), A(27), A(28),
|
||||||
|
A(29)) VL_MT_SAFE {
|
||||||
const char* keyps[VerilatedCovImpBase::MAX_KEYS]
|
const char* keyps[VerilatedCovImpBase::MAX_KEYS]
|
||||||
= {NULL,NULL,NULL, // filename,lineno,page
|
= {NULL, NULL, NULL, // filename,lineno,page
|
||||||
key0,key1,key2,key3,key4,key5,key6,key7,key8,key9,
|
key0, key1, key2, key3, key4, key5, key6, key7, key8, key9,
|
||||||
key10,key11,key12,key13,key14,key15,key16,key17,key18,key19,
|
key10, key11, key12, key13, key14, key15, key16, key17, key18, key19,
|
||||||
key20,key21,key22,key23,key24,key25,key26,key27,key28,key29};
|
key20, key21, key22, key23, key24, key25, key26, key27, key28, key29};
|
||||||
const char* valps[VerilatedCovImpBase::MAX_KEYS]
|
const char* valps[VerilatedCovImpBase::MAX_KEYS]
|
||||||
= {NULL,NULL,NULL, // filename,lineno,page
|
= {NULL, NULL, NULL, // filename,lineno,page
|
||||||
valp0,valp1,valp2,valp3,valp4,valp5,valp6,valp7,valp8,valp9,
|
valp0, valp1, valp2, valp3, valp4, valp5, valp6, valp7, valp8, valp9,
|
||||||
valp10,valp11,valp12,valp13,valp14,valp15,valp16,valp17,valp18,valp19,
|
valp10, valp11, valp12, valp13, valp14, valp15, valp16, valp17, valp18, valp19,
|
||||||
valp20,valp21,valp22,valp23,valp24,valp25,valp26,valp27,valp28,valp29};
|
valp20, valp21, valp22, valp23, valp24, valp25, valp26, valp27, valp28, valp29};
|
||||||
VerilatedCovImp::imp().insertp(keyps, valps);
|
VerilatedCovImp::imp().insertp(keyps, valps);
|
||||||
}
|
}
|
||||||
|
|
||||||
// And versions with fewer arguments (oh for a language with named parameters!)
|
// And versions with fewer arguments (oh for a language with named parameters!)
|
||||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE {
|
void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8),
|
||||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
A(9)) VL_MT_SAFE {
|
||||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
_insertp(C(0), C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), N(10), N(11), N(12),
|
||||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
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));
|
||||||
}
|
}
|
||||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10),
|
||||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE {
|
A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18),
|
||||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
A(19)) VL_MT_SAFE {
|
||||||
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
|
_insertp(C(0), C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), C(10), C(11), C(12),
|
||||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
C(13), C(14), C(15), C(16), C(17), C(18), C(19), N(20), N(21), N(22), N(23), N(24),
|
||||||
|
N(25), N(26), N(27), N(28), N(29));
|
||||||
}
|
}
|
||||||
// Backward compatibility for Verilator
|
// Backward compatibility for Verilator
|
||||||
void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
|
void VerilatedCov::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4),
|
||||||
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),
|
_insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5),
|
||||||
key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(),
|
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),
|
||||||
C(5),C(6),N(7),N(8),N(9),
|
N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29));
|
||||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
|
||||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
|
||||||
}
|
}
|
||||||
#undef A
|
#undef A
|
||||||
#undef C
|
#undef C
|
||||||
|
|||||||
+21
-19
@@ -28,17 +28,17 @@
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
/// Conditionally compile coverage code
|
/// Conditionally compile coverage code
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
#ifdef VM_COVERAGE
|
#ifdef VM_COVERAGE
|
||||||
# define VL_IF_COVER(stmts) \
|
# define VL_IF_COVER(stmts) \
|
||||||
do { \
|
do { stmts; } while (false)
|
||||||
stmts; \
|
|
||||||
} while (false)
|
|
||||||
#else
|
#else
|
||||||
# define VL_IF_COVER(stmts) \
|
# define VL_IF_COVER(stmts) \
|
||||||
do { \
|
do { \
|
||||||
if (false) { stmts; } \
|
if (false) { stmts; } \
|
||||||
} while (false)
|
} while (false)
|
||||||
#endif
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
/// Insert a item for coverage analysis.
|
/// Insert a item for coverage analysis.
|
||||||
@@ -68,16 +68,17 @@
|
|||||||
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
|
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
|
||||||
/// }
|
/// }
|
||||||
|
|
||||||
#define VL_COVER_INSERT(countp,...) \
|
#define VL_COVER_INSERT(countp, ...) \
|
||||||
VL_IF_COVER(VerilatedCov::_inserti(countp); \
|
VL_IF_COVER(VerilatedCov::_inserti(countp); VerilatedCov::_insertf(__FILE__, __LINE__); \
|
||||||
VerilatedCov::_insertf(__FILE__, __LINE__); \
|
|
||||||
VerilatedCov::_insertp("hier", name(), __VA_ARGS__))
|
VerilatedCov::_insertp("hier", name(), __VA_ARGS__))
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
/// Convert VL_COVER_INSERT value arguments to strings
|
/// Convert VL_COVER_INSERT value arguments to strings
|
||||||
|
|
||||||
template< class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
|
template <class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
|
||||||
std::ostringstream os; os<<t; return os.str();
|
std::ostringstream os;
|
||||||
|
os << t;
|
||||||
|
return os.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -89,6 +90,7 @@ template< class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
|
|||||||
|
|
||||||
class VerilatedCov {
|
class VerilatedCov {
|
||||||
VL_UNCOPYABLE(VerilatedCov);
|
VL_UNCOPYABLE(VerilatedCov);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// GLOBAL METHODS
|
// GLOBAL METHODS
|
||||||
/// Return default filename
|
/// Return default filename
|
||||||
@@ -108,18 +110,18 @@ public:
|
|||||||
// We could have just the maximum argument version, but this compiles
|
// We could have just the maximum argument version, but this compiles
|
||||||
// much slower (nearly 2x) than having smaller versions also. However
|
// much slower (nearly 2x) than having smaller versions also. However
|
||||||
// there's not much more gain in having a version for each number of args.
|
// there's not much more gain in having a version for each number of args.
|
||||||
#define K(n) const char* key ## n
|
#define K(n) const char* key##n
|
||||||
#define A(n) const char* key ## n, const char* valp ## n // Argument list
|
#define A(n) const char *key##n, const char *valp##n // Argument list
|
||||||
#define D(n) const char* key ## n = NULL, const char* valp ## n = NULL // Argument list
|
#define D(n) const char *key##n = NULL, const char *valp##n = NULL // Argument list
|
||||||
static void _insertp(D(0),D(1),D(2),D(3),D(4),D(5),D(6),D(7),D(8),D(9));
|
static void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9));
|
||||||
static void _insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)
|
static void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), D(11),
|
||||||
,A(10),D(11),D(12),D(13),D(14),D(15),D(16),D(17),D(18),D(19));
|
D(12), D(13), D(14), D(15), D(16), D(17), D(18), D(19));
|
||||||
static void _insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)
|
static void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), A(11),
|
||||||
,A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)
|
A(12), A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20), D(21),
|
||||||
,A(20),D(21),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,
|
static void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4,
|
||||||
K(4),const std::string& val4, A(5),A(6));
|
A(5), A(6), A(7));
|
||||||
|
|
||||||
#undef K
|
#undef K
|
||||||
#undef A
|
#undef A
|
||||||
|
|||||||
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#define VLCOVGEN_ITEM(string_parsed_by_vlcovgen)
|
#define VLCOVGEN_ITEM(string_parsed_by_vlcovgen)
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
VLCOVGEN_ITEM("name=>'col0_name', short=>'C0', group=>1, default=>undef, descr=>'The column title for the header line of this column'")
|
VLCOVGEN_ITEM("name=>'col0_name', short=>'C0', group=>1, default=>undef, descr=>'The column title for the header line of this column'")
|
||||||
VLCOVGEN_ITEM("name=>'col1_name', short=>'C1', group=>1, default=>undef, ")
|
VLCOVGEN_ITEM("name=>'col1_name', short=>'C1', group=>1, default=>undef, ")
|
||||||
VLCOVGEN_ITEM("name=>'col2_name', short=>'C2', group=>1, default=>undef, ")
|
VLCOVGEN_ITEM("name=>'col2_name', short=>'C2', group=>1, default=>undef, ")
|
||||||
@@ -37,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, ")
|
||||||
@@ -59,6 +61,7 @@ VLCOVGEN_ITEM("name=>'row1', short=>'r1', group=>0, default=>undef, ")
|
|||||||
VLCOVGEN_ITEM("name=>'row2', short=>'r2', group=>0, default=>undef, ")
|
VLCOVGEN_ITEM("name=>'row2', short=>'r2', group=>0, default=>undef, ")
|
||||||
VLCOVGEN_ITEM("name=>'row3', short=>'r3', group=>0, default=>undef, ")
|
VLCOVGEN_ITEM("name=>'row3', short=>'r3', group=>0, default=>undef, ")
|
||||||
VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr=>'For totaling items, weight of this item'")
|
VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr=>'For totaling items, weight of this item'")
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
// VLCOVGEN_CIK_AUTO_EDIT_BEGIN
|
// VLCOVGEN_CIK_AUTO_EDIT_BEGIN
|
||||||
#define VL_CIK_COL0 "c0"
|
#define VL_CIK_COL0 "c0"
|
||||||
@@ -78,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"
|
||||||
@@ -119,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;
|
||||||
|
|||||||
+304
-228
@@ -40,88 +40,80 @@
|
|||||||
// Not supported yet
|
// Not supported yet
|
||||||
#define _VL_SVDPI_UNIMP() \
|
#define _VL_SVDPI_UNIMP() \
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "", \
|
VL_FATAL_MT(__FILE__, __LINE__, "", \
|
||||||
(std::string("%%Error: Unsupported DPI function: ")+VL_FUNC).c_str())
|
(std::string("%%Error: Unsupported DPI function: ") + VL_FUNC).c_str())
|
||||||
|
|
||||||
#define _VL_SVDPI_WARN(...) \
|
#define _VL_SVDPI_WARN(...) VL_PRINTF_MT(__VA_ARGS__)
|
||||||
VL_PRINTF_MT(__VA_ARGS__)
|
|
||||||
|
|
||||||
// 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 'context' keyword.\n");
|
_VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \
|
||||||
|
"'context' keyword.\n")
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
//======================================================================
|
//======================================================================
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// DPI ROUTINES
|
// DPI ROUTINES
|
||||||
|
|
||||||
const char* svDpiVersion() {
|
const char* svDpiVersion() { return "1800-2005"; }
|
||||||
return "1800-2005";
|
|
||||||
}
|
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Bit-select utility functions.
|
// Bit-select utility functions.
|
||||||
|
|
||||||
svBit svGetBitselBit(const svBitVecVal* sp, int bit) {
|
svBit svGetBitselBit(const svBitVecVal* sp, int bit) { return VL_BITRSHIFT_W(sp, bit) & 1; }
|
||||||
return VL_BITRSHIFT_W(sp,bit) & 1;
|
|
||||||
}
|
|
||||||
svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
|
svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
|
||||||
// Not VL_BITRSHIFT_W as sp is a different structure type
|
// Not VL_BITRSHIFT_W as sp is a different structure type
|
||||||
// Verilator doesn't support X/Z so only aval
|
// Verilator doesn't support X/Z so only aval
|
||||||
return (((sp[VL_BITWORD_I(bit)].aval >> VL_BITBIT_I(bit)) & 1)
|
return (((sp[VL_BITWORD_I(bit)].aval >> VL_BITBIT_I(bit)) & 1)
|
||||||
| (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1)<<1));
|
| (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1) << 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) {
|
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(32, bit, dp, s); }
|
||||||
VL_ASSIGNBIT_WI(32, bit, dp, s);
|
|
||||||
}
|
|
||||||
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
|
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
|
||||||
// Verilator doesn't support X/Z so only aval
|
// Verilator doesn't support X/Z so only aval
|
||||||
dp[VL_BITWORD_I(bit)].aval
|
dp[VL_BITWORD_I(bit)].aval = ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
|
||||||
= ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1)<<VL_BITBIT_I(bit)))
|
| ((s & 1) << VL_BITBIT_I(bit)));
|
||||||
| ((s&1)<<VL_BITBIT_I(bit)));
|
dp[VL_BITWORD_I(bit)].bval = ((dp[VL_BITWORD_I(bit)].bval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
|
||||||
dp[VL_BITWORD_I(bit)].bval
|
| ((s & 2) >> 1 << VL_BITBIT_I(bit)));
|
||||||
= ((dp[VL_BITWORD_I(bit)].bval & ~(VL_UL(1)<<VL_BITBIT_I(bit)))
|
|
||||||
| ((s&2)>>1<<VL_BITBIT_I(bit)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void svGetPartselBit(svBitVecVal* dp, const svBitVecVal* sp, int lsb, int width) {
|
void svGetPartselBit(svBitVecVal* dp, const svBitVecVal* sp, int lsb, int width) {
|
||||||
// See also VL_SEL_WWI
|
// See also VL_SEL_WWI
|
||||||
int msb = lsb+width-1;
|
int msb = lsb + width - 1;
|
||||||
int word_shift = VL_BITWORD_I(lsb);
|
int word_shift = VL_BITWORD_I(lsb);
|
||||||
if (VL_BITBIT_I(lsb)==0) {
|
if (VL_BITBIT_I(lsb) == 0) {
|
||||||
// Just a word extract
|
// Just a word extract
|
||||||
for (int i=0; i<VL_WORDS_I(width); ++i) dp[i] = sp[i+word_shift];
|
for (int i = 0; i < VL_WORDS_I(width); ++i) dp[i] = sp[i + word_shift];
|
||||||
} else {
|
} else {
|
||||||
int loffset = lsb & VL_SIZEBITS_I;
|
int loffset = lsb & VL_SIZEBITS_I;
|
||||||
int nbitsfromlow = 32-loffset; // bits that end up in lword (know loffset!=0)
|
int nbitsfromlow = 32 - loffset; // bits that end up in lword (know loffset!=0)
|
||||||
// Middle words
|
// Middle words
|
||||||
int words = VL_WORDS_I(msb-lsb+1);
|
int words = VL_WORDS_I(msb - lsb + 1);
|
||||||
for (int i=0; i<words; ++i) {
|
for (int i = 0; i < words; ++i) {
|
||||||
dp[i] = sp[i+word_shift]>>loffset;
|
dp[i] = sp[i + word_shift] >> loffset;
|
||||||
int upperword = i+word_shift+1;
|
int upperword = i + word_shift + 1;
|
||||||
if (upperword <= static_cast<int>(VL_BITWORD_I(msb))) {
|
if (upperword <= static_cast<int>(VL_BITWORD_I(msb))) {
|
||||||
dp[i] |= sp[upperword] << nbitsfromlow;
|
dp[i] |= sp[upperword] << nbitsfromlow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clean result
|
// Clean result
|
||||||
dp[VL_WORDS_I(width)-1] &= VL_MASK_I(width);
|
dp[VL_WORDS_I(width) - 1] &= VL_MASK_I(width);
|
||||||
}
|
}
|
||||||
void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int lsb, int width) {
|
void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int lsb, int width) {
|
||||||
int msb = lsb+width-1;
|
int msb = lsb + width - 1;
|
||||||
int word_shift = VL_BITWORD_I(lsb);
|
int word_shift = VL_BITWORD_I(lsb);
|
||||||
if (VL_BITBIT_I(lsb)==0) {
|
if (VL_BITBIT_I(lsb) == 0) {
|
||||||
// Just a word extract
|
// Just a word extract
|
||||||
for (int i=0; i<VL_WORDS_I(width); ++i) dp[i] = sp[i+word_shift];
|
for (int i = 0; i < VL_WORDS_I(width); ++i) dp[i] = sp[i + word_shift];
|
||||||
} else {
|
} else {
|
||||||
int loffset = lsb & VL_SIZEBITS_I;
|
int loffset = lsb & VL_SIZEBITS_I;
|
||||||
int nbitsfromlow = 32-loffset; // bits that end up in lword (know loffset!=0)
|
int nbitsfromlow = 32 - loffset; // bits that end up in lword (know loffset!=0)
|
||||||
// Middle words
|
// Middle words
|
||||||
int words = VL_WORDS_I(msb-lsb+1);
|
int words = VL_WORDS_I(msb - lsb + 1);
|
||||||
for (int i=0; i<words; ++i) {
|
for (int i = 0; i < words; ++i) {
|
||||||
dp[i].aval = sp[i+word_shift].aval >> loffset;
|
dp[i].aval = sp[i + word_shift].aval >> loffset;
|
||||||
dp[i].bval = sp[i+word_shift].bval >> loffset;
|
dp[i].bval = sp[i + word_shift].bval >> loffset;
|
||||||
int upperword = i+word_shift+1;
|
int upperword = i + word_shift + 1;
|
||||||
if (upperword <= static_cast<int>(VL_BITWORD_I(msb))) {
|
if (upperword <= static_cast<int>(VL_BITWORD_I(msb))) {
|
||||||
dp[i].aval |= sp[upperword].aval << nbitsfromlow;
|
dp[i].aval |= sp[upperword].aval << nbitsfromlow;
|
||||||
dp[i].bval |= sp[upperword].bval << nbitsfromlow;
|
dp[i].bval |= sp[upperword].bval << nbitsfromlow;
|
||||||
@@ -129,58 +121,56 @@ void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int lsb, int
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Clean result
|
// Clean result
|
||||||
dp[VL_WORDS_I(width)-1].aval &= VL_MASK_I(width);
|
dp[VL_WORDS_I(width) - 1].aval &= VL_MASK_I(width);
|
||||||
dp[VL_WORDS_I(width)-1].bval &= VL_MASK_I(width);
|
dp[VL_WORDS_I(width) - 1].bval &= VL_MASK_I(width);
|
||||||
}
|
}
|
||||||
void svPutPartselBit(svBitVecVal* dp, const svBitVecVal s, int lbit, int width) {
|
void svPutPartselBit(svBitVecVal* dp, const svBitVecVal s, int lbit, int width) {
|
||||||
// See also _VL_INSERT_WI
|
// See also _VL_INSERT_WI
|
||||||
int hbit = lbit+width-1;
|
int hbit = lbit + width - 1;
|
||||||
int hoffset = VL_BITBIT_I(hbit);
|
int hoffset = VL_BITBIT_I(hbit);
|
||||||
int loffset = VL_BITBIT_I(lbit);
|
int loffset = VL_BITBIT_I(lbit);
|
||||||
if (hoffset==VL_SIZEBITS_I && loffset==0) {
|
if (hoffset == VL_SIZEBITS_I && loffset == 0) {
|
||||||
// Fast and common case, word based insertion
|
// Fast and common case, word based insertion
|
||||||
dp[VL_BITWORD_I(lbit)] = s;
|
dp[VL_BITWORD_I(lbit)] = s;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int hword = VL_BITWORD_I(hbit);
|
int hword = VL_BITWORD_I(hbit);
|
||||||
int lword = VL_BITWORD_I(lbit);
|
int lword = VL_BITWORD_I(lbit);
|
||||||
if (hword==lword) { // know < 32 bits because above checks it
|
if (hword == lword) { // know < 32 bits because above checks it
|
||||||
IData insmask = (VL_MASK_I(hoffset-loffset+1))<<loffset;
|
IData insmask = (VL_MASK_I(hoffset - loffset + 1)) << loffset;
|
||||||
dp[lword] = (dp[lword] & ~insmask) | ((s<<loffset) & insmask);
|
dp[lword] = (dp[lword] & ~insmask) | ((s << loffset) & insmask);
|
||||||
} else {
|
} else {
|
||||||
IData hinsmask = (VL_MASK_I(hoffset-0+1))<<0;
|
IData hinsmask = (VL_MASK_I(hoffset - 0 + 1)) << 0;
|
||||||
IData linsmask = (VL_MASK_I(31-loffset+1))<<loffset;
|
IData linsmask = (VL_MASK_I(31 - loffset + 1)) << loffset;
|
||||||
int nbitsonright = 32-loffset; // bits that end up in lword
|
int nbitsonright = 32 - loffset; // bits that end up in lword
|
||||||
dp[lword] = (dp[lword] & ~linsmask) | ((s<<loffset) & linsmask);
|
dp[lword] = (dp[lword] & ~linsmask) | ((s << loffset) & linsmask);
|
||||||
dp[hword] = (dp[hword] & ~hinsmask) | ((s>>nbitsonright) & hinsmask);
|
dp[hword] = (dp[hword] & ~hinsmask) | ((s >> nbitsonright) & hinsmask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// cppcheck-suppress passedByValue
|
// cppcheck-suppress passedByValue
|
||||||
void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int width) {
|
void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int width) {
|
||||||
int hbit = lbit+width-1;
|
int hbit = lbit + width - 1;
|
||||||
int hoffset = VL_BITBIT_I(hbit);
|
int hoffset = VL_BITBIT_I(hbit);
|
||||||
int loffset = VL_BITBIT_I(lbit);
|
int loffset = VL_BITBIT_I(lbit);
|
||||||
if (hoffset==VL_SIZEBITS_I && loffset==0) {
|
if (hoffset == VL_SIZEBITS_I && loffset == 0) {
|
||||||
// Fast and common case, word based insertion
|
// Fast and common case, word based insertion
|
||||||
dp[VL_BITWORD_I(lbit)].aval = s.aval;
|
dp[VL_BITWORD_I(lbit)].aval = s.aval;
|
||||||
dp[VL_BITWORD_I(lbit)].bval = s.bval;
|
dp[VL_BITWORD_I(lbit)].bval = s.bval;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
int hword = VL_BITWORD_I(hbit);
|
int hword = VL_BITWORD_I(hbit);
|
||||||
int lword = VL_BITWORD_I(lbit);
|
int lword = VL_BITWORD_I(lbit);
|
||||||
if (hword==lword) { // know < 32 bits because above checks it
|
if (hword == lword) { // know < 32 bits because above checks it
|
||||||
IData insmask = (VL_MASK_I(hoffset-loffset+1))<<loffset;
|
IData insmask = (VL_MASK_I(hoffset - loffset + 1)) << loffset;
|
||||||
dp[lword].aval = (dp[lword].aval & ~insmask) | ((s.aval<<loffset) & insmask);
|
dp[lword].aval = (dp[lword].aval & ~insmask) | ((s.aval << loffset) & insmask);
|
||||||
dp[lword].bval = (dp[lword].bval & ~insmask) | ((s.bval<<loffset) & insmask);
|
dp[lword].bval = (dp[lword].bval & ~insmask) | ((s.bval << loffset) & insmask);
|
||||||
} else {
|
} else {
|
||||||
IData hinsmask = (VL_MASK_I(hoffset-0+1))<<0;
|
IData hinsmask = (VL_MASK_I(hoffset - 0 + 1)) << 0;
|
||||||
IData linsmask = (VL_MASK_I(31-loffset+1))<<loffset;
|
IData linsmask = (VL_MASK_I(31 - loffset + 1)) << loffset;
|
||||||
int nbitsonright = 32-loffset; // bits that end up in lword
|
int nbitsonright = 32 - loffset; // bits that end up in lword
|
||||||
dp[lword].aval = (dp[lword].aval & ~linsmask) | ((s.aval<<loffset) & linsmask);
|
dp[lword].aval = (dp[lword].aval & ~linsmask) | ((s.aval << loffset) & linsmask);
|
||||||
dp[lword].bval = (dp[lword].bval & ~linsmask) | ((s.bval<<loffset) & linsmask);
|
dp[lword].bval = (dp[lword].bval & ~linsmask) | ((s.bval << loffset) & linsmask);
|
||||||
dp[hword].aval = (dp[hword].aval & ~hinsmask) | ((s.aval>>nbitsonright) & hinsmask);
|
dp[hword].aval = (dp[hword].aval & ~hinsmask) | ((s.aval >> nbitsonright) & hinsmask);
|
||||||
dp[hword].bval = (dp[hword].bval & ~hinsmask) | ((s.bval>>nbitsonright) & hinsmask);
|
dp[hword].bval = (dp[hword].bval & ~hinsmask) | ((s.bval >> nbitsonright) & hinsmask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -204,27 +194,14 @@ static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHa
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// Open array querying functions
|
// Open array querying functions
|
||||||
|
|
||||||
int svLeft(const svOpenArrayHandle h, int d) {
|
int svLeft(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->left(d); }
|
||||||
return _vl_openhandle_varp(h)->left(d);
|
int svRight(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->right(d); }
|
||||||
}
|
int svLow(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->low(d); }
|
||||||
int svRight(const svOpenArrayHandle h, int d) {
|
int svHigh(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->high(d); }
|
||||||
return _vl_openhandle_varp(h)->right(d);
|
int svIncrement(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->increment(d); }
|
||||||
}
|
int svSize(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->elements(d); }
|
||||||
int svLow(const svOpenArrayHandle h, int d) {
|
int svDimensions(const svOpenArrayHandle h) { return _vl_openhandle_varp(h)->udims(); }
|
||||||
return _vl_openhandle_varp(h)->low(d);
|
|
||||||
}
|
|
||||||
int svHigh(const svOpenArrayHandle h, int d) {
|
|
||||||
return _vl_openhandle_varp(h)->high(d);
|
|
||||||
}
|
|
||||||
int svIncrement(const svOpenArrayHandle h, int d) {
|
|
||||||
return _vl_openhandle_varp(h)->increment(d);
|
|
||||||
}
|
|
||||||
int svSize(const svOpenArrayHandle h, int d) {
|
|
||||||
return _vl_openhandle_varp(h)->elements(d);
|
|
||||||
}
|
|
||||||
int svDimensions(const svOpenArrayHandle h) {
|
|
||||||
return _vl_openhandle_varp(h)->udims();
|
|
||||||
}
|
|
||||||
/// Return pointer to open array data, or NULL if not in IEEE standard C layout
|
/// Return pointer to open array data, or NULL if not in IEEE standard C layout
|
||||||
void* svGetArrayPtr(const svOpenArrayHandle h) {
|
void* svGetArrayPtr(const svOpenArrayHandle h) {
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
|
||||||
@@ -242,8 +219,8 @@ int svSizeOfArray(const svOpenArrayHandle h) {
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// Open array access internals
|
// Open array access internals
|
||||||
|
|
||||||
static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp,
|
static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, int indx1,
|
||||||
int nargs, int indx1, int indx2, int indx3) {
|
int indx2, int indx3) {
|
||||||
void* datap = varp->datap();
|
void* datap = varp->datap();
|
||||||
if (VL_UNLIKELY(nargs != varp->udims())) {
|
if (VL_UNLIKELY(nargs != varp->udims())) {
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on"
|
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on"
|
||||||
@@ -251,26 +228,29 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp,
|
|||||||
varp->udims(), nargs);
|
varp->udims(), nargs);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
if (nargs>=1) {
|
if (nargs >= 1) {
|
||||||
datap = varp->datapAdjustIndex(datap, 1, indx1);
|
datap = varp->datapAdjustIndex(datap, 1, indx1);
|
||||||
if (VL_UNLIKELY(!datap)) {
|
if (VL_UNLIKELY(!datap)) {
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 out of bounds; %d outside [%d:%d].\n",
|
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 "
|
||||||
|
"out of bounds; %d outside [%d:%d].\n",
|
||||||
indx1, varp->left(1), varp->right(1));
|
indx1, varp->left(1), varp->right(1));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nargs>=2) {
|
if (nargs >= 2) {
|
||||||
datap = varp->datapAdjustIndex(datap, 2, indx2);
|
datap = varp->datapAdjustIndex(datap, 2, indx2);
|
||||||
if (VL_UNLIKELY(!datap)) {
|
if (VL_UNLIKELY(!datap)) {
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 out of bounds; %d outside [%d:%d].\n",
|
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 "
|
||||||
|
"out of bounds; %d outside [%d:%d].\n",
|
||||||
indx2, varp->left(2), varp->right(2));
|
indx2, varp->left(2), varp->right(2));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nargs>=3) {
|
if (nargs >= 3) {
|
||||||
datap = varp->datapAdjustIndex(datap, 3, indx3);
|
datap = varp->datapAdjustIndex(datap, 3, indx3);
|
||||||
if (VL_UNLIKELY(!datap)) {
|
if (VL_UNLIKELY(!datap)) {
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 out of bounds; %d outside [%d:%d].\n",
|
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 "
|
||||||
|
"out of bounds; %d outside [%d:%d].\n",
|
||||||
indx1, varp->left(3), varp->right(3));
|
indx1, varp->left(3), varp->right(3));
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -280,7 +260,8 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp,
|
|||||||
|
|
||||||
static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) {
|
static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) {
|
||||||
if (VL_UNLIKELY(indx < varp->low(0) || indx > varp->high(0))) {
|
if (VL_UNLIKELY(indx < varp->low(0) || indx > varp->high(0))) {
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function packed index out of bounds; %d outside [%d:%d].\n",
|
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function packed index out of bounds; %d "
|
||||||
|
"outside [%d:%d].\n",
|
||||||
indx, varp->left(0), varp->right(0));
|
indx, varp->left(0), varp->right(0));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -288,8 +269,8 @@ static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return pointer to simulator open array element, or NULL if outside range
|
/// Return pointer to simulator open array element, or NULL if outside range
|
||||||
static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h,
|
static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, int nargs, int indx1, int indx2,
|
||||||
int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
|
int indx3) VL_MT_SAFE {
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
|
||||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
|
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
|
||||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||||
@@ -297,23 +278,25 @@ static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Copy to user bit array from simulator open array
|
/// Copy to user bit array from simulator open array
|
||||||
static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int nargs,
|
||||||
int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
|
int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||||
if (VL_UNLIKELY(!datap)) return;
|
if (VL_UNLIKELY(!datap)) return;
|
||||||
switch (varp->vltype()) {
|
switch (varp->vltype()) {
|
||||||
case VLVT_UINT8: d[0] = *(reinterpret_cast<CData*>(datap)); return;
|
case VLVT_UINT8: d[0] = *(reinterpret_cast<CData*>(datap)); return;
|
||||||
case VLVT_UINT16: d[0] = *(reinterpret_cast<SData*>(datap)); return;
|
case VLVT_UINT16: d[0] = *(reinterpret_cast<SData*>(datap)); return;
|
||||||
case VLVT_UINT32: d[0] = *(reinterpret_cast<IData*>(datap)); return;
|
case VLVT_UINT32: d[0] = *(reinterpret_cast<IData*>(datap)); return;
|
||||||
case VLVT_UINT64: {
|
case VLVT_UINT64: {
|
||||||
WData lwp[2]; VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
WData lwp[2];
|
||||||
d[0] = lwp[0]; d[1] = lwp[1];
|
VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||||
|
d[0] = lwp[0];
|
||||||
|
d[1] = lwp[1];
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VLVT_WDATA: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
for (int i=0; i<VL_WORDS_I(varp->packed().elements()); ++i) d[i] = wdatap[i];
|
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) d[i] = wdatap[i];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -323,25 +306,38 @@ static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Copy to user logic array from simulator open array
|
/// Copy to user logic array from simulator open array
|
||||||
static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int nargs,
|
||||||
int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
|
int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||||
if (VL_UNLIKELY(!datap)) return;
|
if (VL_UNLIKELY(!datap)) return;
|
||||||
switch (varp->vltype()) {
|
switch (varp->vltype()) {
|
||||||
case VLVT_UINT8: d[0].aval = *(reinterpret_cast<CData*>(datap)); d[0].bval=0; return;
|
case VLVT_UINT8:
|
||||||
case VLVT_UINT16: d[0].aval = *(reinterpret_cast<SData*>(datap)); d[0].bval=0; return;
|
d[0].aval = *(reinterpret_cast<CData*>(datap));
|
||||||
case VLVT_UINT32: d[0].aval = *(reinterpret_cast<IData*>(datap)); d[0].bval=0; return;
|
d[0].bval = 0;
|
||||||
|
return;
|
||||||
|
case VLVT_UINT16:
|
||||||
|
d[0].aval = *(reinterpret_cast<SData*>(datap));
|
||||||
|
d[0].bval = 0;
|
||||||
|
return;
|
||||||
|
case VLVT_UINT32:
|
||||||
|
d[0].aval = *(reinterpret_cast<IData*>(datap));
|
||||||
|
d[0].bval = 0;
|
||||||
|
return;
|
||||||
case VLVT_UINT64: {
|
case VLVT_UINT64: {
|
||||||
WData lwp[2]; VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
WData lwp[2];
|
||||||
d[0].aval = lwp[0]; d[0].bval=0;
|
VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||||
d[1].aval = lwp[1]; d[0].bval=0;
|
d[0].aval = lwp[0];
|
||||||
|
d[0].bval = 0;
|
||||||
|
d[1].aval = lwp[1];
|
||||||
|
d[0].bval = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case VLVT_WDATA: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
for (int i=0; i<VL_WORDS_I(varp->packed().elements()); ++i) {
|
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) {
|
||||||
d[i].aval = wdatap[i]; d[i].bval = 0;
|
d[i].aval = wdatap[i];
|
||||||
|
d[i].bval = 0;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -353,19 +349,19 @@ static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandl
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Copy to simulator open array from from user bit array
|
/// Copy to simulator open array from from user bit array
|
||||||
static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int nargs,
|
||||||
int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
|
int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
||||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||||
if (VL_UNLIKELY(!datap)) return;
|
if (VL_UNLIKELY(!datap)) return;
|
||||||
switch (varp->vltype()) {
|
switch (varp->vltype()) {
|
||||||
case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0]; return;
|
case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0]; return;
|
||||||
case VLVT_UINT16: *(reinterpret_cast<SData*>(datap)) = s[0]; return;
|
case VLVT_UINT16: *(reinterpret_cast<SData*>(datap)) = s[0]; return;
|
||||||
case VLVT_UINT32: *(reinterpret_cast<IData*>(datap)) = s[0]; return;
|
case VLVT_UINT32: *(reinterpret_cast<IData*>(datap)) = s[0]; return;
|
||||||
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1], s[0]); break;
|
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1], s[0]); break;
|
||||||
case VLVT_WDATA: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
for (int i=0; i<VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i];
|
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -381,80 +377,82 @@ static void _vl_svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogic
|
|||||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||||
if (VL_UNLIKELY(!datap)) return;
|
if (VL_UNLIKELY(!datap)) return;
|
||||||
switch (varp->vltype()) {
|
switch (varp->vltype()) {
|
||||||
case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0].aval; return;
|
case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0].aval; return;
|
||||||
case VLVT_UINT16: *(reinterpret_cast<SData*>(datap)) = s[0].aval; return;
|
case VLVT_UINT16: *(reinterpret_cast<SData*>(datap)) = s[0].aval; return;
|
||||||
case VLVT_UINT32: *(reinterpret_cast<IData*>(datap)) = s[0].aval; return;
|
case VLVT_UINT32: *(reinterpret_cast<IData*>(datap)) = s[0].aval; return;
|
||||||
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1].aval, s[0].aval); break;
|
case VLVT_UINT64:
|
||||||
|
*(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1].aval, s[0].aval);
|
||||||
|
break;
|
||||||
case VLVT_WDATA: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
for (int i=0; i<VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i].aval;
|
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i].aval;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
|
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
|
||||||
|
varp->vltype());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return bit from simulator open array
|
/// Return bit from simulator open array
|
||||||
static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s,
|
static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, int nargs, int indx1, int indx2,
|
||||||
int nargs, int indx1, int indx2, int indx3, int indx4) VL_MT_SAFE {
|
int indx3, int indx4) VL_MT_SAFE {
|
||||||
// One extra index supported, as need bit number
|
// One extra index supported, as need bit number
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||||
void* datap;
|
void* datap;
|
||||||
int lsb;
|
int lsb;
|
||||||
if (varp->packed().elements()) {
|
if (varp->packed().elements()) {
|
||||||
datap = _vl_sv_adjusted_datap(varp, nargs-1, indx1, indx2, indx3);
|
datap = _vl_sv_adjusted_datap(varp, nargs - 1, indx1, indx2, indx3);
|
||||||
lsb = _vl_sv_adjusted_bit(varp, ((nargs==1) ? indx1
|
lsb = _vl_sv_adjusted_bit(
|
||||||
: (nargs==2) ? indx2
|
varp, ((nargs == 1) ? indx1 : (nargs == 2) ? indx2 : (nargs == 3) ? indx3 : indx4));
|
||||||
: (nargs==3) ? indx3
|
|
||||||
: indx4));
|
|
||||||
} else {
|
} else {
|
||||||
datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||||
lsb = 0;
|
lsb = 0;
|
||||||
}
|
}
|
||||||
if (VL_UNLIKELY(!datap)) return 0;
|
if (VL_UNLIKELY(!datap)) return 0;
|
||||||
switch (varp->vltype()) {
|
switch (varp->vltype()) {
|
||||||
case VLVT_UINT8: return (*(reinterpret_cast<CData*>(datap)) >> lsb) & 1;
|
case VLVT_UINT8: return (*(reinterpret_cast<CData*>(datap)) >> lsb) & 1;
|
||||||
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: return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & VL_ULL(1);
|
case VLVT_UINT64:
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
|
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
|
||||||
|
varp->vltype());
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Update simulator open array from bit
|
/// Update simulator open array from bit
|
||||||
static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value,
|
static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value, int nargs, int indx1,
|
||||||
int nargs, int indx1, int indx2, int indx3, int indx4) VL_MT_SAFE {
|
int indx2, int indx3, int indx4) VL_MT_SAFE {
|
||||||
// One extra index supported, as need bit number
|
// One extra index supported, as need bit number
|
||||||
value &= 1; // Make sure clean
|
value &= 1; // Make sure clean
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
||||||
void* datap;
|
void* datap;
|
||||||
int lsb;
|
int lsb;
|
||||||
if (varp->packed().elements()) {
|
if (varp->packed().elements()) {
|
||||||
datap = _vl_sv_adjusted_datap(varp, nargs-1, indx1, indx2, indx3);
|
datap = _vl_sv_adjusted_datap(varp, nargs - 1, indx1, indx2, indx3);
|
||||||
lsb = _vl_sv_adjusted_bit(varp, ((nargs==1) ? indx1
|
lsb = _vl_sv_adjusted_bit(
|
||||||
: (nargs==2) ? indx2
|
varp, ((nargs == 1) ? indx1 : (nargs == 2) ? indx2 : (nargs == 3) ? indx3 : indx4));
|
||||||
: (nargs==3) ? indx3
|
|
||||||
: indx4));
|
|
||||||
} else {
|
} else {
|
||||||
datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||||
lsb = 0;
|
lsb = 0;
|
||||||
}
|
}
|
||||||
if (VL_UNLIKELY(!datap)) return;
|
if (VL_UNLIKELY(!datap)) return;
|
||||||
switch (varp->vltype()) {
|
switch (varp->vltype()) {
|
||||||
case VLVT_UINT8: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<CData*>(datap)), value); return;
|
case VLVT_UINT8: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<CData*>(datap)), value); return;
|
||||||
case VLVT_UINT16: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<SData*>(datap)), value); return;
|
case VLVT_UINT16: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<SData*>(datap)), value); return;
|
||||||
case VLVT_UINT32: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<IData*>(datap)), value); return;
|
case VLVT_UINT32: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<IData*>(datap)), value); return;
|
||||||
case VLVT_UINT64: VL_ASSIGNBIT_QI(-1, lsb, *(reinterpret_cast<QData*>(datap)), value); return;
|
case VLVT_UINT64: VL_ASSIGNBIT_QI(-1, lsb, *(reinterpret_cast<QData*>(datap)), value); return;
|
||||||
case VLVT_WDATA: VL_ASSIGNBIT_WI(-1, lsb, (reinterpret_cast<WDataOutP>(datap)), value); return;
|
case VLVT_WDATA: VL_ASSIGNBIT_WI(-1, lsb, (reinterpret_cast<WDataOutP>(datap)), value); return;
|
||||||
default:
|
default:
|
||||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
|
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
|
||||||
|
varp->vltype());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -470,10 +468,17 @@ void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) {
|
|||||||
// va_arg is a macro, so need temporaries as used below
|
// va_arg is a macro, so need temporaries as used below
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break;
|
case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0);
|
||||||
datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3); break; }
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: datap = _vl_svGetArrElemPtr(h, -1, 0, 0, 0); break; // Will error
|
default: datap = _vl_svGetArrElemPtr(h, -1, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -489,116 +494,134 @@ void* svGetArrElemPtr3(const svOpenArrayHandle h, int indx1, int indx2, int indx
|
|||||||
return _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
|
return _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, ...) {
|
||||||
int indx1, ...) {
|
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, indx1);
|
va_start(ap, indx1);
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
case 1: _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
_vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
_vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||||
_vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; }
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
_vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: _vl_svPutBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
default: _vl_svPutBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1) {
|
||||||
int indx1) {
|
|
||||||
_vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0);
|
_vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0);
|
||||||
}
|
}
|
||||||
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1,
|
||||||
int indx1, int indx2) {
|
int indx2) {
|
||||||
_vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
_vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||||
}
|
}
|
||||||
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, int indx2,
|
||||||
int indx1, int indx2, int indx3) {
|
int indx3) {
|
||||||
_vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
_vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||||
}
|
}
|
||||||
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, ...) {
|
||||||
int indx1, ...) {
|
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, indx1);
|
va_start(ap, indx1);
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
case 1: _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
_vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
_vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||||
_vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; }
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
_vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: _vl_svPutLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
default: _vl_svPutLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1) {
|
||||||
int indx1) {
|
|
||||||
_vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0);
|
_vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0);
|
||||||
}
|
}
|
||||||
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1,
|
||||||
int indx1, int indx2) {
|
int indx2) {
|
||||||
_vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
_vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||||
}
|
}
|
||||||
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1,
|
||||||
int indx1, int indx2, int indx3) {
|
int indx2, int indx3) {
|
||||||
_vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
_vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// From simulator storage into user space
|
// From simulator storage into user space
|
||||||
|
|
||||||
void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, ...) {
|
||||||
int indx1, ...) {
|
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, indx1);
|
va_start(ap, indx1);
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
case 1: _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
_vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
_vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||||
_vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; }
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
_vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: _vl_svGetBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
default: _vl_svGetBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1) {
|
||||||
int indx1) {
|
|
||||||
_vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0);
|
_vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0);
|
||||||
}
|
}
|
||||||
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) {
|
||||||
int indx1, int indx2) {
|
|
||||||
_vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
_vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||||
}
|
}
|
||||||
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2,
|
||||||
int indx1, int indx2, int indx3) {
|
int indx3) {
|
||||||
_vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
_vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||||
}
|
}
|
||||||
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, ...) {
|
||||||
int indx1, ...) {
|
|
||||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, indx1);
|
va_start(ap, indx1);
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
case 1: _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
_vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
_vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||||
_vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; }
|
break;
|
||||||
|
}
|
||||||
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
_vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: _vl_svGetLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
default: _vl_svGetLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1) {
|
||||||
int indx1) {
|
|
||||||
_vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0);
|
_vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0);
|
||||||
}
|
}
|
||||||
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) {
|
||||||
int indx1, int indx2) {
|
|
||||||
_vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
_vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||||
}
|
}
|
||||||
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2,
|
||||||
int indx1, int indx2, int indx3) {
|
int indx3) {
|
||||||
_vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
_vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -609,12 +632,24 @@ svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
|||||||
va_start(ap, indx1);
|
va_start(ap, indx1);
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break;
|
case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0);
|
||||||
out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); break; }
|
break;
|
||||||
case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int);
|
}
|
||||||
out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); break; }
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
int indx4 = va_arg(ap, int);
|
||||||
|
out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error
|
default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -637,12 +672,24 @@ svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
|||||||
va_start(ap, indx1);
|
va_start(ap, indx1);
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break;
|
case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0);
|
||||||
out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); break; }
|
break;
|
||||||
case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int);
|
}
|
||||||
out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); break; }
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
int indx4 = va_arg(ap, int);
|
||||||
|
out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error
|
default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -667,12 +714,24 @@ void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) {
|
|||||||
va_start(ap, indx1);
|
va_start(ap, indx1);
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break;
|
case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
_vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
_vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0);
|
||||||
_vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); break; }
|
break;
|
||||||
case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int);
|
}
|
||||||
_vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); break; }
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
_vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
int indx4 = va_arg(ap, int);
|
||||||
|
_vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error
|
default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -693,12 +752,24 @@ void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...)
|
|||||||
va_start(ap, indx1);
|
va_start(ap, indx1);
|
||||||
switch (varp->udims()) {
|
switch (varp->udims()) {
|
||||||
case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break;
|
case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break;
|
||||||
case 2: { int indx2=va_arg(ap,int);
|
case 2: {
|
||||||
_vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); break; }
|
int indx2 = va_arg(ap, int);
|
||||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
_vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0);
|
||||||
_vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); break; }
|
break;
|
||||||
case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int);
|
}
|
||||||
_vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); break; }
|
case 3: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
_vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 4: {
|
||||||
|
int indx2 = va_arg(ap, int);
|
||||||
|
int indx3 = va_arg(ap, int);
|
||||||
|
int indx4 = va_arg(ap, int);
|
||||||
|
_vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4);
|
||||||
|
break;
|
||||||
|
}
|
||||||
default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error
|
default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
@@ -707,13 +778,12 @@ void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
|
|||||||
// Verilator doesn't support X/Z so can just call Bit version
|
// Verilator doesn't support X/Z so can just call Bit version
|
||||||
svPutBitArrElem1(d, value, indx1);
|
svPutBitArrElem1(d, value, indx1);
|
||||||
}
|
}
|
||||||
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value,
|
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
|
||||||
int indx1, int indx2) {
|
|
||||||
// Verilator doesn't support X/Z so can just call Bit version
|
// Verilator doesn't support X/Z so can just call Bit version
|
||||||
svPutBitArrElem2(d, value, indx1, indx2);
|
svPutBitArrElem2(d, value, indx1, indx2);
|
||||||
}
|
}
|
||||||
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value,
|
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2,
|
||||||
int indx1, int indx2, int indx3) {
|
int indx3) {
|
||||||
// Verilator doesn't support X/Z so can just call Bit version
|
// Verilator doesn't support X/Z so can just call Bit version
|
||||||
svPutBitArrElem3(d, value, indx1, indx2, indx3);
|
svPutBitArrElem3(d, value, indx1, indx2, indx3);
|
||||||
}
|
}
|
||||||
@@ -722,7 +792,10 @@ void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value,
|
|||||||
// Functions for working with DPI context
|
// Functions for working with DPI context
|
||||||
|
|
||||||
svScope svGetScope() {
|
svScope svGetScope() {
|
||||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return NULL; }
|
if (VL_UNLIKELY(!Verilated::dpiInContext())) {
|
||||||
|
_VL_SVDPI_CONTEXT_WARN();
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
// NOLINTNEXTLINE(google-readability-casting)
|
// NOLINTNEXTLINE(google-readability-casting)
|
||||||
return (svScope)(Verilated::dpiScope());
|
return (svScope)(Verilated::dpiScope());
|
||||||
}
|
}
|
||||||
@@ -746,16 +819,19 @@ svScope svGetScopeFromName(const char* scopeName) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int svPutUserData(const svScope scope, void* userKey, void* userData) {
|
int svPutUserData(const svScope scope, void* userKey, void* userData) {
|
||||||
VerilatedImp::userInsert(scope,userKey,userData);
|
VerilatedImp::userInsert(scope, userKey, userData);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void* svGetUserData(const svScope scope, void* userKey) {
|
void* svGetUserData(const svScope scope, void* userKey) {
|
||||||
return VerilatedImp::userFind(scope,userKey);
|
return VerilatedImp::userFind(scope, userKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
int svGetCallerInfo(const char** fileNamepp, int *lineNumberp) {
|
int svGetCallerInfo(const char** fileNamepp, int* lineNumberp) {
|
||||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return false; }
|
if (VL_UNLIKELY(!Verilated::dpiInContext())) {
|
||||||
|
_VL_SVDPI_CONTEXT_WARN();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if (VL_LIKELY(fileNamepp)) *fileNamepp = Verilated::dpiFilenamep(); // thread local
|
if (VL_LIKELY(fileNamepp)) *fileNamepp = Verilated::dpiFilenamep(); // thread local
|
||||||
if (VL_LIKELY(lineNumberp)) *lineNumberp = Verilated::dpiLineno(); // thread local
|
if (VL_LIKELY(lineNumberp)) *lineNumberp = Verilated::dpiLineno(); // thread local
|
||||||
return true;
|
return true;
|
||||||
|
|||||||
+33
-19
@@ -32,45 +32,59 @@
|
|||||||
//===================================================================
|
//===================================================================
|
||||||
// SETTING OPERATORS
|
// SETTING OPERATORS
|
||||||
|
|
||||||
/// Return WData from svBitVecVal
|
/// Convert svBitVecVal to Verilator internal data
|
||||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE {
|
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE {
|
||||||
int words = VL_WORDS_I(obits);
|
int words = VL_WORDS_I(obits);
|
||||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
|
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i];
|
||||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits);
|
||||||
}
|
}
|
||||||
/// Return svBitVecVal from WData
|
static inline QData VL_SET_Q_SVBV(const svBitVecVal* lwp) VL_MT_SAFE {
|
||||||
|
return _VL_SET_QII(lwp[1], lwp[0]);
|
||||||
|
}
|
||||||
|
static inline IData VL_SET_I_SVBV(const svBitVecVal* lwp) VL_MT_SAFE { return lwp[0]; }
|
||||||
|
|
||||||
|
/// Convert Verilator internal data to svBitVecVal
|
||||||
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
||||||
int words = VL_WORDS_I(obits);
|
int words = VL_WORDS_I(obits);
|
||||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
|
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i];
|
||||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits);
|
||||||
|
}
|
||||||
|
static inline void VL_SET_SVBV_I(int, svBitVecVal* owp, IData ld) VL_MT_SAFE { owp[0] = ld; }
|
||||||
|
static inline void VL_SET_SVBV_Q(int, svBitVecVal* owp, QData ld) VL_MT_SAFE {
|
||||||
|
VL_SET_WQ(owp, ld);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert svLogicVecVal to/from WData
|
/// Convert svLogicVecVal to Verilator internal data
|
||||||
/// Note these functions ignore X/Z in svLogicVecVal
|
/// Note these functions ignore X/Z in svLogicVecVal
|
||||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, const svLogicVecVal* lwp) VL_MT_SAFE {
|
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||||
int words = VL_WORDS_I(obits);
|
int words = VL_WORDS_I(obits);
|
||||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i].aval;
|
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i].aval;
|
||||||
owp[words-1] = lwp[words-1].aval & VL_MASK_I(obits);
|
owp[words - 1] = lwp[words - 1].aval & VL_MASK_I(obits);
|
||||||
}
|
}
|
||||||
static inline QData VL_SET_Q_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE {
|
static inline QData VL_SET_Q_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||||
return _VL_SET_QII(lwp[1].aval, lwp[0].aval);
|
return _VL_SET_QII(lwp[1].aval, lwp[0].aval);
|
||||||
}
|
}
|
||||||
static inline IData VL_SET_I_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE {
|
static inline IData VL_SET_I_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE { return lwp[0].aval; }
|
||||||
return lwp[0].aval;
|
|
||||||
}
|
/// Convert Verilator internal data to svLogicVecVal
|
||||||
|
/// Note these functions never create X/Z in svLogicVecVal
|
||||||
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
||||||
int words = VL_WORDS_I(obits);
|
int words = VL_WORDS_I(obits);
|
||||||
for (int i=0; i<words; ++i) owp[i].bval=0;
|
for (int i = 0; i < words; ++i) owp[i].bval = 0;
|
||||||
for (int i=0; i<words-1; ++i) owp[i].aval=lwp[i];
|
for (int i = 0; i < words - 1; ++i) owp[i].aval = lwp[i];
|
||||||
owp[words-1].aval = lwp[words-1] & VL_MASK_I(obits);
|
owp[words - 1].aval = lwp[words - 1] & VL_MASK_I(obits);
|
||||||
}
|
}
|
||||||
static inline void VL_SET_SVLV_I(int, svLogicVecVal* owp, IData ld) VL_MT_SAFE {
|
static inline void VL_SET_SVLV_I(int, svLogicVecVal* owp, IData ld) VL_MT_SAFE {
|
||||||
owp[0].aval=ld; owp[0].bval=0;
|
owp[0].aval = ld;
|
||||||
|
owp[0].bval = 0;
|
||||||
}
|
}
|
||||||
static inline void VL_SET_SVLV_Q(int, svLogicVecVal* owp, QData ld) VL_MT_SAFE {
|
static inline void VL_SET_SVLV_Q(int, svLogicVecVal* owp, QData ld) VL_MT_SAFE {
|
||||||
WData lwp[2]; VL_SET_WQ(lwp,ld);
|
WData lwp[2];
|
||||||
owp[0].aval=lwp[0]; owp[0].bval=0;
|
VL_SET_WQ(lwp, ld);
|
||||||
owp[1].aval=lwp[1]; owp[1].bval=0;
|
owp[0].aval = lwp[0];
|
||||||
|
owp[0].bval = 0;
|
||||||
|
owp[1].aval = lwp[1];
|
||||||
|
owp[1].bval = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|||||||
+134
-91
@@ -17,13 +17,14 @@
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
// SPDIFF_OFF
|
// SPDIFF_OFF
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
#define __STDC_LIMIT_MACROS // UINT64_MAX
|
#define __STDC_LIMIT_MACROS // UINT64_MAX
|
||||||
#include "verilatedos.h"
|
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
#include "verilated_fst_c.h"
|
#include "verilated_fst_c.h"
|
||||||
|
|
||||||
// GTKWave configuration
|
// GTKWave configuration
|
||||||
#ifdef VL_TRACE_THREADED
|
#ifdef VL_TRACE_FST_WRITER_THREAD
|
||||||
# define HAVE_LIBPTHREAD
|
# define HAVE_LIBPTHREAD
|
||||||
# define FST_WRITER_PARALLEL
|
# define FST_WRITER_PARALLEL
|
||||||
#endif
|
#endif
|
||||||
@@ -35,68 +36,50 @@
|
|||||||
#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
|
||||||
|
|
||||||
//=============================================================================
|
// clang-format on
|
||||||
|
|
||||||
class VerilatedFstCallInfo {
|
//=============================================================================
|
||||||
protected:
|
// Specialization of the generics for this trace format
|
||||||
friend class VerilatedFst;
|
|
||||||
VerilatedFstCallback_t m_initcb; ///< Initialization Callback function
|
#define VL_DERIVED_T VerilatedFst
|
||||||
VerilatedFstCallback_t m_fullcb; ///< Full Dumping Callback function
|
#include "verilated_trace_imp.cpp"
|
||||||
VerilatedFstCallback_t m_changecb; ///< Incremental Dumping Callback function
|
#undef VL_DERIVED_T
|
||||||
void* m_userthis; ///< Fake "this" for caller
|
|
||||||
vluint32_t m_code; ///< Starting code number
|
|
||||||
// CONSTRUCTORS
|
|
||||||
VerilatedFstCallInfo(VerilatedFstCallback_t icb, VerilatedFstCallback_t fcb,
|
|
||||||
VerilatedFstCallback_t changecb, void* ut)
|
|
||||||
: m_initcb(icb)
|
|
||||||
, m_fullcb(fcb)
|
|
||||||
, m_changecb(changecb)
|
|
||||||
, m_userthis(ut)
|
|
||||||
, m_code(1) {}
|
|
||||||
~VerilatedFstCallInfo() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedFst
|
// VerilatedFst
|
||||||
|
|
||||||
VerilatedFst::VerilatedFst(void* fst)
|
VerilatedFst::VerilatedFst(void* fst)
|
||||||
: m_fst(fst)
|
: m_fst(fst)
|
||||||
, m_fullDump(true)
|
, m_symbolp(NULL)
|
||||||
, m_nextCode(1)
|
, m_strbuf(NULL) {}
|
||||||
, m_scopeEscape('.') {
|
|
||||||
m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad
|
VerilatedFst::~VerilatedFst() {
|
||||||
|
if (m_fst) fstWriterClose(m_fst);
|
||||||
|
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = NULL);
|
||||||
|
if (m_strbuf) VL_DO_CLEAR(delete[] m_strbuf, m_strbuf = NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||||
m_assertOne.check();
|
m_assertOne.check();
|
||||||
m_fst = fstWriterCreate(filename, 1);
|
m_fst = fstWriterCreate(filename, 1);
|
||||||
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
|
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
|
||||||
#ifdef VL_TRACE_THREADED
|
fstWriterSetTimescaleFromString(m_fst, timeResStr().c_str()); // lintok-begin-on-ref
|
||||||
|
#ifdef VL_TRACE_FST_WRITER_THREAD
|
||||||
fstWriterSetParallelMode(m_fst, 1);
|
fstWriterSetParallelMode(m_fst, 1);
|
||||||
#endif
|
#endif
|
||||||
m_curScope.clear();
|
|
||||||
m_nextCode = 1;
|
|
||||||
|
|
||||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
m_curScope.clear();
|
||||||
VerilatedFstCallInfo* cip = m_callbacks[ent];
|
|
||||||
cip->m_code = m_nextCode;
|
VerilatedTrace<VerilatedFst>::traceInit();
|
||||||
// Initialize; callbacks will call decl* which update m_nextCode
|
|
||||||
(cip->m_initcb)(this, cip->m_userthis, cip->m_code);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clear the scope stack
|
// Clear the scope stack
|
||||||
std::list<std::string>::iterator it = m_curScope.begin();
|
std::list<std::string>::iterator it = m_curScope.begin();
|
||||||
@@ -104,47 +87,67 @@ void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
|||||||
fstWriterSetUpscope(m_fst);
|
fstWriterSetUpscope(m_fst);
|
||||||
it = m_curScope.erase(it);
|
it = m_curScope.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// convert m_code2symbol into an array for fast lookup
|
||||||
|
if (!m_symbolp) {
|
||||||
|
m_symbolp = new fstHandle[nextCode()];
|
||||||
|
for (Code2SymbolType::iterator it = m_code2symbol.begin(); it != m_code2symbol.end();
|
||||||
|
++it) {
|
||||||
|
m_symbolp[it->first] = it->second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_code2symbol.clear();
|
||||||
|
|
||||||
|
// Allocate string buffer for arrays
|
||||||
|
if (!m_strbuf) { m_strbuf = new char[maxBits() + 32]; }
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedFst::module(const std::string& name) {
|
void VerilatedFst::close() {
|
||||||
m_module = name;
|
m_assertOne.check();
|
||||||
|
VerilatedTrace<VerilatedFst>::close();
|
||||||
|
fstWriterClose(m_fst);
|
||||||
|
m_fst = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedFst::flush() {
|
||||||
|
VerilatedTrace<VerilatedFst>::flush();
|
||||||
|
fstWriterFlushContext(m_fst);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VerilatedFst::emitTimeChange(vluint64_t timeui) { fstWriterEmitTimeChange(m_fst, timeui); }
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Decl
|
// Decl
|
||||||
|
|
||||||
void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
|
void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
|
||||||
unsigned int minValbits,
|
unsigned int minValbits, const char** itemNamesp,
|
||||||
const char** itemNamesp, const char** itemValuesp) {
|
const char** itemValuesp) {
|
||||||
fstEnumHandle enumNum = fstWriterCreateEnumTable(m_fst, name, elements,
|
fstEnumHandle enumNum
|
||||||
minValbits, itemNamesp, itemValuesp);
|
= fstWriterCreateEnumTable(m_fst, name, elements, minValbits, itemNamesp, itemValuesp);
|
||||||
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;
|
||||||
|
|
||||||
// Make sure deduplicate tracking increments for future declarations
|
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
|
||||||
int codesNeeded = 1 + int(bits / 32);
|
|
||||||
//Not supported: if (tri) codesNeeded *= 2; // Space in change array for __en signals
|
|
||||||
m_nextCode = std::max(m_nextCode, code + codesNeeded);
|
|
||||||
|
|
||||||
std::pair<Code2SymbolType::iterator, bool> p
|
std::pair<Code2SymbolType::iterator, bool> p
|
||||||
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
|
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
|
||||||
std::istringstream nameiss(name);
|
std::istringstream nameiss(name);
|
||||||
std::istream_iterator<std::string> beg(nameiss), end;
|
std::istream_iterator<std::string> beg(nameiss);
|
||||||
|
std::istream_iterator<std::string> end;
|
||||||
std::list<std::string> tokens(beg, end); // Split name
|
std::list<std::string> tokens(beg, end); // Split name
|
||||||
std::string symbol_name(tokens.back());
|
std::string symbol_name(tokens.back());
|
||||||
tokens.pop_back(); // Remove symbol name from hierarchy
|
tokens.pop_back(); // Remove symbol name from hierarchy
|
||||||
tokens.insert(tokens.begin(), m_module); // Add current module to the hierarchy
|
tokens.insert(tokens.begin(), moduleName()); // Add current module to the hierarchy
|
||||||
|
|
||||||
// Find point where current and new scope diverge
|
// Find point where current and new scope diverge
|
||||||
std::list<std::string>::iterator cur_it = m_curScope.begin();
|
std::list<std::string>::iterator cur_it = m_curScope.begin();
|
||||||
std::list<std::string>::iterator new_it = tokens.begin();
|
std::list<std::string>::iterator new_it = tokens.begin();
|
||||||
while (cur_it != m_curScope.end() && new_it != tokens.end()) {
|
while (cur_it != m_curScope.end() && new_it != tokens.end()) {
|
||||||
if (*cur_it != *new_it)
|
if (*cur_it != *new_it) break;
|
||||||
break;
|
|
||||||
++cur_it;
|
++cur_it;
|
||||||
++new_it;
|
++new_it;
|
||||||
}
|
}
|
||||||
@@ -172,48 +175,88 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f
|
|||||||
fstWriterEmitEnumTableRef(m_fst, enumNum);
|
fstWriterEmitEnumTableRef(m_fst, enumNum);
|
||||||
}
|
}
|
||||||
if (p.second) { // New
|
if (p.second) { // New
|
||||||
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), 0);
|
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
|
||||||
assert(p.first->second);
|
assert(p.first->second);
|
||||||
} else { // Alias
|
} else { // Alias
|
||||||
fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), p.first->second);
|
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), p.first->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
void VerilatedFst::declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
// Callbacks
|
fstVarType vartype, bool array, int arraynum) {
|
||||||
|
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 0, 0);
|
||||||
void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
|
}
|
||||||
VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
|
void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
m_assertOne.check();
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||||
if (VL_UNLIKELY(isOpen())) {
|
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||||
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
|
}
|
||||||
+ " called with already open file");
|
void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||||
}
|
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||||
VerilatedFstCallInfo* cip = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis);
|
}
|
||||||
m_callbacks.push_back(cip);
|
void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||||
|
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||||
|
}
|
||||||
|
void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
|
fstVarType vartype, bool array, int arraynum) {
|
||||||
|
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 63, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
//=============================================================================
|
// Note: emit* are only ever called from one place (full* in
|
||||||
// Dumping
|
// verilated_trace_imp.cpp, which is included in this file at the top),
|
||||||
|
// so always inline them.
|
||||||
|
|
||||||
void VerilatedFst::dump(vluint64_t timeui) {
|
VL_ATTR_ALWINLINE
|
||||||
if (!isOpen()) return;
|
void VerilatedFst::emitBit(vluint32_t code, CData newval) {
|
||||||
if (VL_UNLIKELY(m_fullDump)) {
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0");
|
||||||
m_fullDump = false; // No more need for next dump to be full
|
|
||||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
|
||||||
VerilatedFstCallInfo* cip = m_callbacks[ent];
|
|
||||||
(cip->m_fullcb)(this, cip->m_userthis, cip->m_code);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
fstWriterEmitTimeChange(m_fst, timeui);
|
|
||||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
|
||||||
VerilatedFstCallInfo* cip = m_callbacks[ent];
|
|
||||||
(cip->m_changecb)(this, cip->m_userthis, cip->m_code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//********************************************************************
|
VL_ATTR_ALWINLINE
|
||||||
// Local Variables:
|
void VerilatedFst::emitCData(vluint32_t code, CData newval, int bits) {
|
||||||
// End:
|
char buf[VL_BYTESIZE];
|
||||||
|
cvtCDataToStr(buf, newval << (VL_BYTESIZE - bits));
|
||||||
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
VL_ATTR_ALWINLINE
|
||||||
|
void VerilatedFst::emitSData(vluint32_t code, SData newval, int bits) {
|
||||||
|
char buf[VL_SHORTSIZE];
|
||||||
|
cvtSDataToStr(buf, newval << (VL_SHORTSIZE - bits));
|
||||||
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
VL_ATTR_ALWINLINE
|
||||||
|
void VerilatedFst::emitIData(vluint32_t code, IData newval, int bits) {
|
||||||
|
char buf[VL_IDATASIZE];
|
||||||
|
cvtIDataToStr(buf, newval << (VL_IDATASIZE - bits));
|
||||||
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
VL_ATTR_ALWINLINE
|
||||||
|
void VerilatedFst::emitQData(vluint32_t code, QData newval, int bits) {
|
||||||
|
char buf[VL_QUADSIZE];
|
||||||
|
cvtQDataToStr(buf, newval << (VL_QUADSIZE - bits));
|
||||||
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
VL_ATTR_ALWINLINE
|
||||||
|
void VerilatedFst::emitWData(vluint32_t code, const WData* newvalp, int bits) {
|
||||||
|
int words = VL_WORDS_I(bits);
|
||||||
|
char* wp = m_strbuf;
|
||||||
|
// Convert the most significant word
|
||||||
|
const int bitsInMSW = VL_BITBIT_E(bits) ? VL_BITBIT_E(bits) : VL_EDATASIZE;
|
||||||
|
cvtEDataToStr(wp, newvalp[--words] << (VL_EDATASIZE - bitsInMSW));
|
||||||
|
wp += bitsInMSW;
|
||||||
|
// Convert the remaining words
|
||||||
|
while (words > 0) {
|
||||||
|
cvtEDataToStr(wp, newvalp[--words]);
|
||||||
|
wp += VL_EDATASIZE;
|
||||||
|
}
|
||||||
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
VL_ATTR_ALWINLINE
|
||||||
|
void VerilatedFst::emitDouble(vluint32_t code, double newval) {
|
||||||
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
|
||||||
|
}
|
||||||
|
|||||||
+79
-142
@@ -20,8 +20,8 @@
|
|||||||
#ifndef _VERILATED_FST_C_H_
|
#ifndef _VERILATED_FST_C_H_
|
||||||
#define _VERILATED_FST_C_H_ 1
|
#define _VERILATED_FST_C_H_ 1
|
||||||
|
|
||||||
#include "verilatedos.h"
|
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
|
#include "verilated_trace.h"
|
||||||
|
|
||||||
#include "gtkwave/fstapi.h"
|
#include "gtkwave/fstapi.h"
|
||||||
|
|
||||||
@@ -30,163 +30,98 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class VerilatedFst;
|
|
||||||
class VerilatedFstCallInfo;
|
|
||||||
typedef void (*VerilatedFstCallback_t)(VerilatedFst* vcdp, void* userthis, vluint32_t code);
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedFst
|
// VerilatedFst
|
||||||
/// Base class to create a Verilator FST dump
|
/// Base class to create a Verilator FST dump
|
||||||
/// This is an internally used class - see VerilatedFstC for what to call from applications
|
/// This is an internally used class - see VerilatedFstC for what to call from applications
|
||||||
|
|
||||||
class VerilatedFst {
|
class VerilatedFst : public VerilatedTrace<VerilatedFst> {
|
||||||
|
private:
|
||||||
|
// Give the superclass access to private bits (to avoid virtual functions)
|
||||||
|
friend class VerilatedTrace<VerilatedFst>;
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// FST specific internals
|
||||||
|
|
||||||
typedef std::map<vluint32_t, fstHandle> Code2SymbolType;
|
typedef std::map<vluint32_t, fstHandle> Code2SymbolType;
|
||||||
typedef std::map<int, fstEnumHandle> Local2FstDtype;
|
typedef std::map<int, fstEnumHandle> Local2FstDtype;
|
||||||
typedef std::vector<VerilatedFstCallInfo*> CallbackVec;
|
|
||||||
private:
|
|
||||||
void* m_fst;
|
void* m_fst;
|
||||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
|
||||||
bool m_fullDump;
|
|
||||||
vluint32_t m_nextCode; ///< Next code number to assign
|
|
||||||
char m_scopeEscape;
|
|
||||||
std::string m_module;
|
|
||||||
CallbackVec m_callbacks; ///< Routines to perform dumping
|
|
||||||
Code2SymbolType m_code2symbol;
|
Code2SymbolType m_code2symbol;
|
||||||
Local2FstDtype m_local2fstdtype;
|
Local2FstDtype m_local2fstdtype;
|
||||||
std::list<std::string> m_curScope;
|
std::list<std::string> m_curScope;
|
||||||
|
fstHandle* m_symbolp; ///< same as m_code2symbol, but as an array
|
||||||
|
char* m_strbuf; ///< String buffer long enough to hold maxBits() chars
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedFst);
|
VL_UNCOPYABLE(VerilatedFst);
|
||||||
void declSymbol(vluint32_t code, const char* name,
|
void declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||||
bool array, int arraynum, vluint32_t len, vluint32_t bits);
|
|
||||||
// helpers
|
protected:
|
||||||
std::vector<char> m_valueStrBuffer;
|
//=========================================================================
|
||||||
|
// Implementation of VerilatedTrace interface
|
||||||
|
|
||||||
|
// Implementations of protected virtual methods for VerilatedTrace
|
||||||
|
void emitTimeChange(vluint64_t timeui) VL_OVERRIDE;
|
||||||
|
|
||||||
|
// Hooks called from VerilatedTrace
|
||||||
|
bool preFullDump() VL_OVERRIDE { return isOpen(); }
|
||||||
|
bool preChangeDump() VL_OVERRIDE { return isOpen(); }
|
||||||
|
|
||||||
|
// Implementations of duck-typed methods for VerilatedTrace. These are
|
||||||
|
// called from only one place (namely full*) so always inline them.
|
||||||
|
inline void emitBit(vluint32_t code, CData newval);
|
||||||
|
inline void emitCData(vluint32_t code, CData newval, int bits);
|
||||||
|
inline void emitSData(vluint32_t code, SData 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 emitWData(vluint32_t code, const WData* newvalp, int bits);
|
||||||
|
inline void emitDouble(vluint32_t code, double newval);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VerilatedFst(void* fst=NULL);
|
//=========================================================================
|
||||||
~VerilatedFst() { if (m_fst == NULL) { fstWriterClose(m_fst); } }
|
// External interface to client code
|
||||||
void changeThread() { m_assertOne.changeThread(); }
|
|
||||||
bool isOpen() const { return m_fst != NULL; }
|
explicit VerilatedFst(void* fst = NULL);
|
||||||
|
~VerilatedFst();
|
||||||
|
|
||||||
|
/// Open the file; call isOpen() to see if errors
|
||||||
void open(const char* filename) VL_MT_UNSAFE;
|
void open(const char* filename) VL_MT_UNSAFE;
|
||||||
void flush() VL_MT_UNSAFE { fstWriterFlushContext(m_fst); }
|
/// Close the file
|
||||||
void close() VL_MT_UNSAFE {
|
void close() VL_MT_UNSAFE;
|
||||||
m_assertOne.check();
|
/// Flush any remaining data to this file
|
||||||
fstWriterClose(m_fst);
|
void flush() VL_MT_UNSAFE;
|
||||||
m_fst = NULL;
|
/// Is file open?
|
||||||
}
|
bool isOpen() const { return m_fst != NULL; }
|
||||||
void set_time_unit(const char* unitp) { fstWriterSetTimescaleFromString(m_fst, unitp); }
|
|
||||||
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
|
|
||||||
|
|
||||||
void set_time_resolution(const char* unitp) { if (unitp) {} }
|
//=========================================================================
|
||||||
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
|
// Internal interface to Verilator generated code
|
||||||
|
|
||||||
// double timescaleToDouble(const char* unitp);
|
|
||||||
// std::string doubleToTimescale(double value);
|
|
||||||
|
|
||||||
/// Change character that splits scopes. Note whitespace are ALWAYS escapes.
|
|
||||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
|
||||||
/// Is this an escape?
|
|
||||||
bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; }
|
|
||||||
/// Inside dumping routines, called each cycle to make the dump
|
|
||||||
void dump(vluint64_t timeui);
|
|
||||||
/// Inside dumping routines, declare callbacks for tracings
|
|
||||||
void addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
|
|
||||||
VerilatedFstCallback_t changecb,
|
|
||||||
void* userthis) VL_MT_UNSAFE_ONE;
|
|
||||||
|
|
||||||
/// Inside dumping routines, declare a module
|
|
||||||
void module(const std::string& name);
|
|
||||||
/// Inside dumping routines, declare a data type
|
/// Inside dumping routines, declare a data type
|
||||||
void declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
|
void declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
|
||||||
unsigned int minValbits,
|
unsigned int minValbits, const char** itemNamesp, const char** itemValuesp);
|
||||||
const char** itemNamesp, const char** itemValuesp);
|
|
||||||
/// Inside dumping routines, declare a signal
|
/// Inside dumping routines, declare a signal
|
||||||
void declBit(vluint32_t code, const char* name,
|
void declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
fstVarType vartype, bool array, int arraynum);
|
||||||
bool array, int arraynum) {
|
void declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1);
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||||
}
|
void declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
void declBus(vluint32_t code, const char* name,
|
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
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,
|
void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||||
msb - lsb + 1);
|
fstVarType vartype, bool array, int arraynum);
|
||||||
}
|
|
||||||
void declDouble(vluint32_t code, const char* name,
|
|
||||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
|
||||||
bool array, int arraynum) {
|
|
||||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64);
|
|
||||||
}
|
|
||||||
void declFloat(vluint32_t code, const char* name,
|
|
||||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
|
||||||
bool array, int arraynum) {
|
|
||||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32);
|
|
||||||
}
|
|
||||||
void declQuad(vluint32_t code, const char* name,
|
|
||||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
|
||||||
bool array, int arraynum, int msb, int lsb) {
|
|
||||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
|
||||||
msb - lsb + 1);
|
|
||||||
}
|
|
||||||
void declArray(vluint32_t code, const char* name,
|
|
||||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
|
||||||
bool array, int arraynum, int msb, int lsb) {
|
|
||||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
|
||||||
msb - lsb + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Inside dumping routines, dump one signal if it has changed
|
|
||||||
void chgBit(vluint32_t code, const vluint32_t newval) {
|
|
||||||
fstWriterEmitValueChange(m_fst, m_code2symbol[code], newval ? "1" : "0");
|
|
||||||
}
|
|
||||||
void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
|
|
||||||
fstWriterEmitValueChange32(m_fst, m_code2symbol[code], bits, newval);
|
|
||||||
}
|
|
||||||
void chgDouble(vluint32_t code, const double newval) {
|
|
||||||
double val = newval;
|
|
||||||
fstWriterEmitValueChange(m_fst, m_code2symbol[code], &val);
|
|
||||||
}
|
|
||||||
void chgFloat(vluint32_t code, const float newval) {
|
|
||||||
double val = (double)newval;
|
|
||||||
fstWriterEmitValueChange(m_fst, m_code2symbol[code], &val);
|
|
||||||
}
|
|
||||||
void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
|
||||||
fstWriterEmitValueChange64(m_fst, m_code2symbol[code], bits, newval);
|
|
||||||
}
|
|
||||||
void chgArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
|
||||||
fstWriterEmitValueChangeVec32(m_fst, m_code2symbol[code], bits, newval);
|
|
||||||
}
|
|
||||||
|
|
||||||
void fullBit(vluint32_t code, const vluint32_t newval) {
|
|
||||||
chgBit(code, newval); }
|
|
||||||
void fullBus(vluint32_t code, const vluint32_t newval, int bits) {
|
|
||||||
chgBus(code, newval, bits); }
|
|
||||||
void fullDouble(vluint32_t code, const double newval) {
|
|
||||||
chgDouble(code, newval); }
|
|
||||||
void fullFloat(vluint32_t code, const float newval) {
|
|
||||||
chgFloat(code, newval); }
|
|
||||||
void fullQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
|
||||||
chgQuad(code, newval, bits); }
|
|
||||||
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
|
||||||
chgArray(code, newval, bits); }
|
|
||||||
|
|
||||||
void declTriBit(vluint32_t code, const char* name, int arraynum);
|
|
||||||
void declTriBus(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
|
||||||
void declTriQuad(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
|
||||||
void declTriArray(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
|
||||||
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
|
|
||||||
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
|
|
||||||
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
|
|
||||||
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits);
|
|
||||||
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);
|
|
||||||
void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
|
|
||||||
void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
|
|
||||||
void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
|
|
||||||
void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Declare specialization here as it's used in VerilatedFstC just below
|
||||||
|
template <> void VerilatedTrace<VerilatedFst>::dump(vluint64_t timeui);
|
||||||
|
template <> void VerilatedTrace<VerilatedFst>::set_time_unit(const char* unitp);
|
||||||
|
template <> void VerilatedTrace<VerilatedFst>::set_time_unit(const std::string& unit);
|
||||||
|
template <> void VerilatedTrace<VerilatedFst>::set_time_resolution(const char* unitp);
|
||||||
|
template <> void VerilatedTrace<VerilatedFst>::set_time_resolution(const std::string& unit);
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedFstC
|
// VerilatedFstC
|
||||||
/// Create a FST dump file in C standalone (no SystemC) simulations.
|
/// Create a FST dump file in C standalone (no SystemC) simulations.
|
||||||
@@ -198,12 +133,14 @@ class VerilatedFstC {
|
|||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedFstC);
|
VL_UNCOPYABLE(VerilatedFstC);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VerilatedFstC(void* filep=NULL) : m_sptrace(filep) {}
|
explicit VerilatedFstC(void* filep = NULL)
|
||||||
|
: m_sptrace(filep) {}
|
||||||
~VerilatedFstC() { close(); }
|
~VerilatedFstC() { close(); }
|
||||||
/// Routines can only be called from one thread; allow next call from different thread
|
/// Routines can only be called from one thread; allow next call from different thread
|
||||||
void changeThread() { spTrace()->changeThread(); }
|
void changeThread() { spTrace()->changeThread(); }
|
||||||
public:
|
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
/// Is file open?
|
/// Is file open?
|
||||||
bool isOpen() const { return m_sptrace.isOpen(); }
|
bool isOpen() const { return m_sptrace.isOpen(); }
|
||||||
@@ -222,13 +159,13 @@ public:
|
|||||||
void dump(vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
void dump(vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||||
void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||||
/// Set time units (s/ms, defaults to ns)
|
/// Set time units (s/ms, defaults to ns)
|
||||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
/// For Verilated models, these propage from the Verilated default --timeunit
|
||||||
void set_time_unit(const char* unitp) { m_sptrace.set_time_unit(unitp); }
|
void set_time_unit(const char* unitp) { m_sptrace.set_time_unit(unitp); }
|
||||||
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
|
void set_time_unit(const std::string& unit) { m_sptrace.set_time_unit(unit); }
|
||||||
/// Set time resolution (s/ms, defaults to ns)
|
/// Set time resolution (s/ms, defaults to ns)
|
||||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
/// For Verilated models, these propage from the Verilated default --timeunit
|
||||||
void set_time_resolution(const char* unitp) { m_sptrace.set_time_resolution(unitp); }
|
void set_time_resolution(const char* unitp) { m_sptrace.set_time_resolution(unitp); }
|
||||||
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
|
void set_time_resolution(const std::string& unit) { m_sptrace.set_time_resolution(unit); }
|
||||||
|
|
||||||
/// Internal class access
|
/// Internal class access
|
||||||
inline VerilatedFst* spTrace() { return &m_sptrace; };
|
inline VerilatedFst* spTrace() { return &m_sptrace; };
|
||||||
|
|||||||
+71
-31
@@ -28,6 +28,7 @@
|
|||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
@@ -82,8 +83,11 @@ public:
|
|||||||
|
|
||||||
template <std::size_t T_Words> class VlWide {
|
template <std::size_t T_Words> class VlWide {
|
||||||
WData m_storage[T_Words];
|
WData m_storage[T_Words];
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Default constructor/destructor/copy are fine
|
// cppcheck-suppress uninitVar
|
||||||
|
VlWide() {}
|
||||||
|
~VlWide() {}
|
||||||
const WData& at(size_t index) const { return m_storage[index]; }
|
const WData& at(size_t index) const { return m_storage[index]; }
|
||||||
WData& at(size_t index) { return m_storage[index]; }
|
WData& at(size_t index) { return m_storage[index]; }
|
||||||
WData* data() { return &m_storage[0]; }
|
WData* data() { return &m_storage[0]; }
|
||||||
@@ -95,13 +99,11 @@ public:
|
|||||||
|
|
||||||
// Convert a C array to std::array reference by pointer magic, without copy.
|
// Convert a C array to std::array reference by pointer magic, without copy.
|
||||||
// Data type (second argument) is so the function template can automatically generate.
|
// Data type (second argument) is so the function template can automatically generate.
|
||||||
template <std::size_t T_Words>
|
template <std::size_t T_Words> VlWide<T_Words>& VL_CVT_W_A(WDataInP inp, const VlWide<T_Words>&) {
|
||||||
VlWide<T_Words>& VL_CVT_W_A(WDataInP inp, const VlWide<T_Words>&) {
|
|
||||||
return *((VlWide<T_Words>*)inp);
|
return *((VlWide<T_Words>*)inp);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <std::size_t T_Words>
|
template <std::size_t T_Words> std::string VL_TO_STRING(const VlWide<T_Words>& obj) {
|
||||||
std::string VL_TO_STRING(const VlWide<T_Words>& obj) {
|
|
||||||
return VL_TO_STRING_W(T_Words, obj.data());
|
return VL_TO_STRING_W(T_Words, obj.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -114,6 +116,7 @@ template <class T_Key, class T_Value> class VlAssocArray {
|
|||||||
private:
|
private:
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef std::map<T_Key, T_Value> Map;
|
typedef std::map<T_Key, T_Value> Map;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename Map::const_iterator const_iterator;
|
typedef typename Map::const_iterator const_iterator;
|
||||||
|
|
||||||
@@ -187,8 +190,11 @@ public:
|
|||||||
// Accessing. Verilog: v = assoc[index]
|
// Accessing. Verilog: v = assoc[index]
|
||||||
const T_Value& at(const T_Key& index) const {
|
const T_Value& at(const T_Key& index) const {
|
||||||
typename Map::iterator it = m_map.find(index);
|
typename Map::iterator it = m_map.find(index);
|
||||||
if (it == m_map.end()) return m_defaultValue;
|
if (it == m_map.end()) {
|
||||||
else return it->second;
|
return m_defaultValue;
|
||||||
|
} else {
|
||||||
|
return it->second;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// For save/restore
|
// For save/restore
|
||||||
const_iterator begin() const { return m_map.begin(); }
|
const_iterator begin() const { return m_map.begin(); }
|
||||||
@@ -251,6 +257,7 @@ template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
|
|||||||
private:
|
private:
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef std::deque<T_Value> Deque;
|
typedef std::deque<T_Value> Deque;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
typedef typename Deque::const_iterator const_iterator;
|
typedef typename Deque::const_iterator const_iterator;
|
||||||
|
|
||||||
@@ -274,7 +281,9 @@ public:
|
|||||||
int size() const { return m_deque.size(); }
|
int size() const { return m_deque.size(); }
|
||||||
// Clear array. Verilog: function void delete([input index])
|
// Clear array. Verilog: function void delete([input index])
|
||||||
void clear() { m_deque.clear(); }
|
void clear() { m_deque.clear(); }
|
||||||
void erase(size_t index) { if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); }
|
void erase(size_t index) {
|
||||||
|
if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index);
|
||||||
|
}
|
||||||
|
|
||||||
// Dynamic array new[] becomes a renew()
|
// Dynamic array new[] becomes a renew()
|
||||||
void renew(size_t size) {
|
void renew(size_t size) {
|
||||||
@@ -282,7 +291,7 @@ public:
|
|||||||
m_deque.resize(size, atDefault());
|
m_deque.resize(size, atDefault());
|
||||||
}
|
}
|
||||||
// Dynamic array new[]() becomes a renew_copy()
|
// Dynamic array new[]() becomes a renew_copy()
|
||||||
void renew_copy(size_t size, const VlQueue<T_Value,T_MaxSize>& rhs) {
|
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
clear();
|
clear();
|
||||||
} else {
|
} else {
|
||||||
@@ -303,12 +312,16 @@ public:
|
|||||||
// function value_t q.pop_front();
|
// function value_t q.pop_front();
|
||||||
T_Value pop_front() {
|
T_Value pop_front() {
|
||||||
if (m_deque.empty()) return m_defaultValue;
|
if (m_deque.empty()) return m_defaultValue;
|
||||||
T_Value v = m_deque.front(); m_deque.pop_front(); return v;
|
T_Value v = m_deque.front();
|
||||||
|
m_deque.pop_front();
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
// function value_t q.pop_back();
|
// function value_t q.pop_back();
|
||||||
T_Value pop_back() {
|
T_Value pop_back() {
|
||||||
if (m_deque.empty()) return m_defaultValue;
|
if (m_deque.empty()) return m_defaultValue;
|
||||||
T_Value v = m_deque.back(); m_deque.pop_back(); return v;
|
T_Value v = m_deque.back();
|
||||||
|
m_deque.pop_back();
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting. Verilog: assoc[index] = v
|
// Setting. Verilog: assoc[index] = v
|
||||||
@@ -320,15 +333,19 @@ public:
|
|||||||
if (VL_UNLIKELY(index >= m_deque.size())) {
|
if (VL_UNLIKELY(index >= m_deque.size())) {
|
||||||
s_throwAway = atDefault();
|
s_throwAway = atDefault();
|
||||||
return s_throwAway;
|
return s_throwAway;
|
||||||
|
} else {
|
||||||
|
return m_deque[index];
|
||||||
}
|
}
|
||||||
else return m_deque[index];
|
|
||||||
}
|
}
|
||||||
// Accessing. Verilog: v = assoc[index]
|
// Accessing. Verilog: v = assoc[index]
|
||||||
const T_Value& at(size_t index) const {
|
const T_Value& at(size_t index) const {
|
||||||
static T_Value s_throwAway;
|
static T_Value s_throwAway;
|
||||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||||
if (VL_UNLIKELY(index >= m_deque.size())) return atDefault();
|
if (VL_UNLIKELY(index >= m_deque.size())) {
|
||||||
else return m_deque[index];
|
return atDefault();
|
||||||
|
} else {
|
||||||
|
return m_deque[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// function void q.insert(index, value);
|
// function void q.insert(index, value);
|
||||||
void insert(size_t index, const T_Value& value) {
|
void insert(size_t index, const T_Value& value) {
|
||||||
@@ -352,36 +369,56 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T_Value>
|
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
||||||
std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
|
||||||
return obj.to_string();
|
return obj.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===================================================================
|
||||||
|
// Verilog class reference container
|
||||||
|
// There are no multithreaded locks on this; the base variable must
|
||||||
|
// be protected by other means
|
||||||
|
//
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#if (defined(_MSC_VER) && _MSC_VER >= 1900) || (__cplusplus >= 201103L)
|
||||||
|
# define VlClassRef std::shared_ptr
|
||||||
|
#else
|
||||||
|
# define VlClassRef VlClassRef__SystemVerilog_class_support_requires_a_C11_or_newer_compiler
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
template <class T> // T typically of type VlClassRef<x>
|
||||||
|
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
|
||||||
|
if (VL_UNLIKELY(!t)) Verilated::nullPointerError(filename, linenum);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Conversion functions
|
// Conversion functions
|
||||||
|
|
||||||
extern std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) VL_MT_SAFE;
|
extern std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) VL_MT_SAFE;
|
||||||
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
|
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
|
||||||
WData lw[VL_WQ_WORDS_E]; VL_SET_WQ(lw, lhs);
|
WData lw[VL_WQ_WORDS_E];
|
||||||
|
VL_SET_WQ(lw, lhs);
|
||||||
return VL_CVT_PACK_STR_NW(VL_WQ_WORDS_E, lw);
|
return VL_CVT_PACK_STR_NW(VL_WQ_WORDS_E, lw);
|
||||||
}
|
}
|
||||||
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE {
|
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE { return lhs; }
|
||||||
return lhs;
|
|
||||||
}
|
|
||||||
inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
|
inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
|
||||||
WData lw[VL_WQ_WORDS_E]; VL_SET_WI(lw, lhs);
|
WData lw[VL_WQ_WORDS_E];
|
||||||
|
VL_SET_WI(lw, lhs);
|
||||||
return VL_CVT_PACK_STR_NW(1, lw);
|
return VL_CVT_PACK_STR_NW(1, lw);
|
||||||
}
|
}
|
||||||
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) VL_PURE {
|
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) VL_PURE {
|
||||||
return lhs + rhs;
|
return lhs + rhs;
|
||||||
}
|
}
|
||||||
inline std::string VL_REPLICATEN_NNQ(int,int,int, const std::string& lhs, IData rep) VL_PURE {
|
inline std::string VL_REPLICATEN_NNQ(int, int, int, const std::string& lhs, IData rep) VL_PURE {
|
||||||
std::string out; out.reserve(lhs.length() * rep);
|
std::string out;
|
||||||
for (unsigned times=0; times<rep; ++times) out += lhs;
|
out.reserve(lhs.length() * rep);
|
||||||
|
for (unsigned times = 0; times < rep; ++times) out += lhs;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits,
|
inline std::string VL_REPLICATEN_NNI(int obits, int lbits, int rbits, const std::string& lhs,
|
||||||
const std::string& lhs, IData rep) VL_PURE {
|
IData rep) VL_PURE {
|
||||||
return VL_REPLICATEN_NNQ(obits, lbits, rbits, lhs, rep);
|
return VL_REPLICATEN_NNQ(obits, lbits, rbits, lhs, rep);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,18 +426,21 @@ inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
|
|||||||
extern std::string VL_TOLOWER_NN(const std::string& ld);
|
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_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
|
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) 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;
|
||||||
extern void VL_WRITEMEM_N(bool hex, int bits, QData depth, int array_lsb,
|
extern void VL_WRITEMEM_N(bool hex, int bits, QData depth, int array_lsb,
|
||||||
const std::string& filename, const void* memp, QData start,
|
const std::string& filename, const void* memp, QData start,
|
||||||
QData end) VL_MT_SAFE;
|
QData end) VL_MT_SAFE;
|
||||||
extern IData VL_SSCANF_INX(int lbits, const std::string& ld,
|
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
|
||||||
const char* formatp, ...) VL_MT_SAFE;
|
extern void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp,
|
||||||
extern void VL_SFORMAT_X(int obits_ignored, std::string& output,
|
...) VL_MT_SAFE;
|
||||||
const char* formatp, ...) VL_MT_SAFE;
|
|
||||||
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
|
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
|
||||||
|
extern void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix,
|
||||||
|
int width) VL_MT_SAFE;
|
||||||
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE;
|
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE;
|
||||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, CData& rdr) VL_MT_SAFE {
|
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, CData& rdr) VL_MT_SAFE {
|
||||||
WData rwp[2]; // WData must always be at least 2
|
WData rwp[2]; // WData must always be at least 2
|
||||||
|
|||||||
+238
-75
@@ -19,6 +19,7 @@
|
|||||||
#ifndef _VERILATED_IMP_H_
|
#ifndef _VERILATED_IMP_H_
|
||||||
#define _VERILATED_IMP_H_ 1 ///< Header Guard
|
#define _VERILATED_IMP_H_ 1 ///< Header Guard
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_) && !defined(_VERILATED_VPI_CPP_)
|
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_) && !defined(_VERILATED_VPI_CPP_)
|
||||||
# error "verilated_imp.h only to be included by verilated*.cpp internals"
|
# error "verilated_imp.h only to be included by verilated*.cpp internals"
|
||||||
#endif
|
#endif
|
||||||
@@ -31,10 +32,12 @@
|
|||||||
#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>
|
||||||
#endif
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
class VerilatedScope;
|
class VerilatedScope;
|
||||||
|
|
||||||
@@ -47,9 +50,11 @@ class VerilatedMsg {
|
|||||||
public:
|
public:
|
||||||
// TYPES
|
// TYPES
|
||||||
struct Cmp {
|
struct Cmp {
|
||||||
bool operator() (const VerilatedMsg& a, const VerilatedMsg& b) const {
|
bool operator()(const VerilatedMsg& a, const VerilatedMsg& b) const {
|
||||||
return a.mtaskId() < b.mtaskId(); }
|
return a.mtaskId() < b.mtaskId();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
vluint32_t m_mtaskId; ///< MTask that did enqueue
|
vluint32_t m_mtaskId; ///< MTask that did enqueue
|
||||||
@@ -86,11 +91,12 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
VL_UNCOPYABLE(VerilatedEvalMsgQueue);
|
VL_UNCOPYABLE(VerilatedEvalMsgQueue);
|
||||||
|
|
||||||
public:
|
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;
|
||||||
}
|
}
|
||||||
@@ -122,6 +128,7 @@ public:
|
|||||||
/// Each thread has a local queue to build up messages until the end of the eval() call
|
/// Each thread has a local queue to build up messages until the end of the eval() call
|
||||||
class VerilatedThreadMsgQueue {
|
class VerilatedThreadMsgQueue {
|
||||||
std::queue<VerilatedMsg> m_queue;
|
std::queue<VerilatedMsg> m_queue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedThreadMsgQueue() {}
|
VerilatedThreadMsgQueue() {}
|
||||||
@@ -129,6 +136,7 @@ public:
|
|||||||
// The only call of this with a non-empty queue is a fatal error.
|
// The only call of this with a non-empty queue is a fatal error.
|
||||||
// So this does not flush the queue, as the destination queue is not known to this class.
|
// So this does not flush the queue, as the destination queue is not known to this class.
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
||||||
// METHODS
|
// METHODS
|
||||||
@@ -136,6 +144,7 @@ private:
|
|||||||
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
||||||
return t_s;
|
return t_s;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/// Add message to queue, called by producer
|
/// Add message to queue, called by producer
|
||||||
static void post(const VerilatedMsg& msg) VL_MT_SAFE {
|
static void post(const VerilatedMsg& msg) VL_MT_SAFE {
|
||||||
@@ -160,11 +169,31 @@ 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
|
||||||
|
|
||||||
class VerilatedImp {
|
class VerilatedImp {
|
||||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||||
|
protected:
|
||||||
|
friend class Verilated;
|
||||||
|
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef std::vector<std::string> ArgVec;
|
typedef std::vector<std::string> ArgVec;
|
||||||
@@ -174,44 +203,72 @@ class VerilatedImp {
|
|||||||
// MEMBERS
|
// MEMBERS
|
||||||
static VerilatedImp s_s; ///< Static Singleton; One and only static this
|
static VerilatedImp s_s; ///< Static Singleton; One and only static this
|
||||||
|
|
||||||
// Nothing here is save-restored; users expected to re-register appropriately
|
struct Serialized { // All these members serialized/deserialized
|
||||||
|
int m_timeFormatUnits; // $timeformat units
|
||||||
|
int m_timeFormatPrecision; // $timeformat number of decimal places
|
||||||
|
int m_timeFormatWidth; // $timeformat character width
|
||||||
|
enum { UNITS_NONE = 99 }; // Default based on precision
|
||||||
|
Serialized()
|
||||||
|
: m_timeFormatUnits(UNITS_NONE)
|
||||||
|
, m_timeFormatPrecision(0)
|
||||||
|
, m_timeFormatWidth(20) {}
|
||||||
|
~Serialized() {}
|
||||||
|
} m_ser;
|
||||||
|
|
||||||
VerilatedMutex m_argMutex; ///< Protect m_argVec, m_argVecLoaded
|
VerilatedMutex m_sergMutex; ///< Protect m_ser
|
||||||
ArgVec m_argVec VL_GUARDED_BY(m_argMutex); ///< Argument list (NOT save-restored, may want different results)
|
struct SerializedG { // All these members serialized/deserialized and guarded
|
||||||
bool m_argVecLoaded VL_GUARDED_BY(m_argMutex); ///< Ever loaded argument list
|
std::string m_timeFormatSuffix; // $timeformat printf format
|
||||||
|
} m_serg VL_GUARDED_BY(m_sergMutex);
|
||||||
|
|
||||||
VerilatedMutex m_userMapMutex; ///< Protect m_userMap
|
// Nothing below here is save-restored; users expected to re-register appropriately
|
||||||
UserMap m_userMap VL_GUARDED_BY(m_userMapMutex); ///< Map of <(scope,userkey), userData>
|
|
||||||
|
|
||||||
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
|
VerilatedMutex m_argMutex; ///< Protect m_argVec, m_argVecLoaded
|
||||||
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); ///< Map of <scope_name, scope pointer>
|
/// Argument list (NOT save-restored, may want different results)
|
||||||
|
ArgVec m_argVec VL_GUARDED_BY(m_argMutex);
|
||||||
|
bool m_argVecLoaded VL_GUARDED_BY(m_argMutex); ///< Ever loaded argument list
|
||||||
|
|
||||||
VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap
|
VerilatedMutex m_userMapMutex; ///< Protect m_userMap
|
||||||
VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex); ///< Map the represents scope hierarchy
|
UserMap m_userMap VL_GUARDED_BY(m_userMapMutex); ///< Map of <(scope,userkey), userData>
|
||||||
|
|
||||||
|
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
|
||||||
|
/// Map of <scope_name, scope pointer>
|
||||||
|
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex);
|
||||||
|
|
||||||
|
VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap
|
||||||
|
/// Map the represents scope hierarchy
|
||||||
|
VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex);
|
||||||
|
|
||||||
// Slow - somewhat static:
|
// Slow - somewhat static:
|
||||||
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
|
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
|
||||||
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); ///< Map of <export_func_proto, func number>
|
/// Map of <export_func_proto, func number>
|
||||||
int m_exportNext VL_GUARDED_BY(m_exportMutex); ///< Next export funcnum
|
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex);
|
||||||
|
int m_exportNext VL_GUARDED_BY(m_exportMutex); ///< Next export funcnum
|
||||||
|
|
||||||
// File I/O
|
// File I/O
|
||||||
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
|
||||||
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex); ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
/// List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||||
|
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() {}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VL_UNCOPYABLE(VerilatedImp);
|
VL_UNCOPYABLE(VerilatedImp);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// METHODS - debug
|
// METHODS - debug
|
||||||
static void internalsDump() VL_MT_SAFE;
|
static void internalsDump() VL_MT_SAFE;
|
||||||
@@ -222,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)) {
|
||||||
@@ -238,11 +295,12 @@ public:
|
|||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
|
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
|
||||||
static void commandArgVl(const std::string& arg);
|
static void commandArgVl(const std::string& arg);
|
||||||
static bool commandArgVlValue(const std::string& arg,
|
static bool commandArgVlValue(const std::string& arg, const std::string& prefix,
|
||||||
const std::string& prefix, std::string& valuer);
|
std::string& valuer);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// METHODS - user scope tracking
|
// METHODS - user scope tracking
|
||||||
@@ -250,23 +308,26 @@ 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()) it->second = userData;
|
if (it != s_s.m_userMap.end()) {
|
||||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
it->second = userData;
|
||||||
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
|
} else {
|
||||||
|
s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
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_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
if (VL_UNLIKELY(it == s_s.m_userMap.end())) return NULL;
|
||||||
else return NULL;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
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++);
|
||||||
@@ -276,12 +337,15 @@ 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) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
if (first) {
|
||||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
|
VL_PRINTF_MT(" userDump:\n");
|
||||||
it->first.first, it->first.second, it->second);
|
first = false;
|
||||||
|
}
|
||||||
|
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n", it->first.first,
|
||||||
|
it->first.second, it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -289,28 +353,28 @@ 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_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
if (VL_UNLIKELY(it == s_s.m_nameMap.end())) return NULL;
|
||||||
else return NULL;
|
return it->second;
|
||||||
}
|
}
|
||||||
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) {
|
||||||
@@ -328,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 {
|
||||||
@@ -347,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++));
|
||||||
@@ -357,17 +421,17 @@ 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
|
||||||
+" but no such DPI export function name exists in ANY model");
|
+ " but no such DPI export function name exists in ANY model");
|
||||||
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
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;
|
||||||
@@ -375,46 +439,145 @@ 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) {
|
||||||
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
if (first) {
|
||||||
|
VL_PRINTF_MT(" exportDump:\n");
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// We don't free up m_exportMap until the end, because we can't be sure
|
// We don't free up m_exportMap until the end, because we can't be sure
|
||||||
// what other models are using the assigned funcnum's.
|
// what other models are using the assigned funcnum's.
|
||||||
|
|
||||||
|
public: // But only for verilated*.cpp
|
||||||
|
// METHODS - timeformat
|
||||||
|
static std::string timeFormatSuffix() VL_MT_SAFE;
|
||||||
|
static void timeFormatSuffix(const std::string& value) VL_MT_SAFE;
|
||||||
|
static int timeFormatUnits() VL_MT_SAFE {
|
||||||
|
if (s_s.m_ser.m_timeFormatUnits == Serialized::UNITS_NONE) {
|
||||||
|
return Verilated::timeprecision();
|
||||||
|
}
|
||||||
|
return s_s.m_ser.m_timeFormatUnits;
|
||||||
|
}
|
||||||
|
static int timeFormatPrecision() VL_MT_SAFE { return s_s.m_ser.m_timeFormatPrecision; }
|
||||||
|
static int timeFormatWidth() VL_MT_SAFE { return s_s.m_ser.m_timeFormatWidth; }
|
||||||
|
static void timeFormatUnits(int value) VL_MT_SAFE;
|
||||||
|
static void timeFormatPrecision(int value) VL_MT_SAFE;
|
||||||
|
static void timeFormatWidth(int value) VL_MT_SAFE;
|
||||||
|
|
||||||
public: // But only for verilated*.cpp
|
public: // But only for verilated*.cpp
|
||||||
// METHODS - file IO
|
// METHODS - file IO
|
||||||
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
static IData fdNewMcd(const char* filenamep) VL_MT_SAFE {
|
||||||
|
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||||
|
if (s_s.m_fdFreeMct.empty()) return 0;
|
||||||
|
IData idx = s_s.m_fdFreeMct.back();
|
||||||
|
s_s.m_fdFreeMct.pop_back();
|
||||||
|
s_s.m_fdps[idx] = fopen(filenamep, "w");
|
||||||
|
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return 0;
|
||||||
|
return (1 << idx);
|
||||||
|
}
|
||||||
|
static IData fdNew(const char* filenamep, const char* modep) VL_MT_SAFE {
|
||||||
|
FILE* fp = fopen(filenamep, modep);
|
||||||
if (VL_UNLIKELY(!fp)) return 0;
|
if (VL_UNLIKELY(!fp)) return 0;
|
||||||
// Bit 31 indicates it's a descriptor not a MCD
|
// Bit 31 indicates it's a descriptor not a MCD
|
||||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
const VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||||
if (s_s.m_fdFree.empty()) {
|
if (s_s.m_fdFree.empty()) {
|
||||||
// Need to create more space in m_fdps and m_fdFree
|
// Need to create more space in m_fdps and m_fdFree
|
||||||
size_t start = s_s.m_fdps.size();
|
const size_t start = std::max(31ul + 1ul + 3ul, s_s.m_fdps.size());
|
||||||
s_s.m_fdps.resize(start*2);
|
const size_t excess = 10;
|
||||||
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
|
s_s.m_fdps.resize(start + excess);
|
||||||
|
std::fill(s_s.m_fdps.begin() + start, s_s.m_fdps.end(), (FILE*)0);
|
||||||
|
s_s.m_fdFree.resize(excess);
|
||||||
|
for (std::size_t i = 0, id = start; i < s_s.m_fdFree.size(); ++i, ++id) {
|
||||||
|
s_s.m_fdFree[i] = id;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
|
IData idx = s_s.m_fdFree.back();
|
||||||
|
s_s.m_fdFree.pop_back();
|
||||||
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;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can
|
||||||
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
// Version 2.0.
|
||||||
|
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilator: Common include for target specific intrinsics.
|
||||||
|
///
|
||||||
|
/// Code using machine specific intrinsics for optimization should
|
||||||
|
/// include this header rather than directly including he target
|
||||||
|
/// specific headers. We provide macros to check for availability
|
||||||
|
/// of instruction sets, and a common mechanism to disable them.
|
||||||
|
///
|
||||||
|
//*************************************************************************
|
||||||
|
|
||||||
|
#ifndef _VERILATED_INTRINSICS_H_
|
||||||
|
#define _VERILATED_INTRINSICS_H_ 1 ///< Header Guard
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
// Use VL_DISABLE_INTRINSICS to disable all intrinsics based optimization
|
||||||
|
#if !defined(VL_DISABLE_INTRINSICS) && !defined(VL_PORTABLE_ONLY)
|
||||||
|
# if defined(__SSE2__) && !defined(VL_DISABLE_SSE2)
|
||||||
|
# define VL_HAVE_SSE2 1
|
||||||
|
# include <emmintrin.h>
|
||||||
|
# endif
|
||||||
|
# if defined(__AVX2__) && defined(VL_HAVE_SSE2) && !defined(VL_DISABLE_AVX2)
|
||||||
|
# define VL_HAVE_AVX2 1
|
||||||
|
# include <immintrin.h>
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
+43
-36
@@ -23,6 +23,7 @@
|
|||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||||
# include <io.h>
|
# include <io.h>
|
||||||
#else
|
#else
|
||||||
@@ -38,9 +39,11 @@
|
|||||||
#ifndef O_CLOEXEC
|
#ifndef O_CLOEXEC
|
||||||
# define O_CLOEXEC 0
|
# define O_CLOEXEC 0
|
||||||
#endif
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file
|
static const char* const VLTSAVE_HEADER_STR
|
||||||
|
= "verilatorsave01\n"; ///< Value of first bytes of each file
|
||||||
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -48,22 +51,21 @@ static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last b
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Searalization
|
// Searalization
|
||||||
|
|
||||||
bool VerilatedDeserialize::readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
bool VerilatedDeserialize::readDiffers(const void* __restrict datap,
|
||||||
|
size_t size) VL_MT_UNSAFE_ONE {
|
||||||
bufferCheck();
|
bufferCheck();
|
||||||
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
|
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
|
||||||
vluint8_t miss = 0;
|
vluint8_t miss = 0;
|
||||||
while (size--) {
|
while (size--) miss |= (*dp++ ^ *m_cp++);
|
||||||
miss |= (*dp++ ^ *m_cp++);
|
return (miss != 0);
|
||||||
}
|
|
||||||
return (miss!=0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap,
|
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap,
|
||||||
size_t size) VL_MT_UNSAFE_ONE {
|
size_t size) VL_MT_UNSAFE_ONE {
|
||||||
if (VL_UNLIKELY(readDiffers(datap, size))) {
|
if (VL_UNLIKELY(readDiffers(datap, size))) {
|
||||||
std::string fn = filename();
|
std::string fn = filename();
|
||||||
std::string msg = "Can't deserialize save-restore file as was made from different model:"
|
std::string msg
|
||||||
+filename();
|
= "Can't deserialize save-restore file as was made from different model:" + filename();
|
||||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
@@ -77,19 +79,21 @@ void VerilatedSerialize::header() VL_MT_UNSAFE_ONE {
|
|||||||
|
|
||||||
// Verilated doesn't do it itself, as if we're not using save/restore
|
// Verilated doesn't do it itself, as if we're not using save/restore
|
||||||
// it doesn't need to compile this stuff in
|
// it doesn't need to compile this stuff in
|
||||||
os.write(Verilated::serializedPtr(), Verilated::serializedSize());
|
os.write(Verilated::serialized1Ptr(), Verilated::serialized1Size());
|
||||||
|
os.write(Verilated::serialized2Ptr(), Verilated::serialized2Size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
||||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
||||||
std::string fn = filename();
|
std::string fn = filename();
|
||||||
std::string msg = std::string("Can't deserialize; file has wrong header signature: ")
|
std::string msg
|
||||||
+filename();
|
= std::string("Can't deserialize; file has wrong header signature: ") + filename();
|
||||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
os.read(Verilated::serialized1Ptr(), Verilated::serialized1Size());
|
||||||
|
os.read(Verilated::serialized2Ptr(), Verilated::serialized2Size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
|
void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
|
||||||
@@ -103,7 +107,7 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
|||||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
||||||
std::string fn = filename();
|
std::string fn = filename();
|
||||||
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ")
|
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ")
|
||||||
+filename();
|
+ filename();
|
||||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
@@ -119,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, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC
|
m_fd = ::open(filenamep,
|
||||||
, 0666);
|
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
|
||||||
if (m_fd<0) {
|
if (m_fd < 0) {
|
||||||
// User code can check isOpen()
|
// User code can check isOpen()
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
return;
|
return;
|
||||||
@@ -142,13 +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
|
m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666);
|
||||||
, 0666);
|
if (m_fd < 0) {
|
||||||
if (m_fd<0) {
|
|
||||||
// User code can check isOpen()
|
// User code can check isOpen()
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
return;
|
return;
|
||||||
@@ -186,18 +189,20 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
|
|||||||
vluint8_t* wp = m_bufp;
|
vluint8_t* wp = m_bufp;
|
||||||
while (true) {
|
while (true) {
|
||||||
ssize_t remaining = (m_cp - wp);
|
ssize_t remaining = (m_cp - wp);
|
||||||
if (remaining==0) break;
|
if (remaining == 0) break;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,29 +214,31 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
|
|||||||
if (VL_UNLIKELY(!isOpen())) return;
|
if (VL_UNLIKELY(!isOpen())) return;
|
||||||
// Move remaining characters down to start of buffer. (No memcpy, overlaps allowed)
|
// Move remaining characters down to start of buffer. (No memcpy, overlaps allowed)
|
||||||
vluint8_t* rp = m_bufp;
|
vluint8_t* rp = m_bufp;
|
||||||
for (vluint8_t* sp=m_cp; sp < m_endp;) *rp++ = *sp++; // Overlaps
|
for (vluint8_t* sp = m_cp; sp < m_endp; *rp++ = *sp++) {} // Overlaps
|
||||||
m_endp = m_bufp + (m_endp - m_cp);
|
m_endp = m_bufp + (m_endp - m_cp);
|
||||||
m_cp = m_bufp; // Reset buffer
|
m_cp = m_bufp; // Reset buffer
|
||||||
// Read into buffer starting at m_endp
|
// Read into buffer starting at m_endp
|
||||||
while (true) {
|
while (true) {
|
||||||
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
|
ssize_t remaining = (m_bufp + bufferSize() - m_endp);
|
||||||
if (remaining==0) break;
|
if (remaining == 0) break;
|
||||||
errno = 0;
|
errno = 0;
|
||||||
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
|
||||||
// need to check eof each character.
|
// need to check eof each character.
|
||||||
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
|
while (m_endp < m_bufp + bufferSize()) *m_endp++ = '\0';
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-20
@@ -46,6 +46,7 @@ protected:
|
|||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedSerialize);
|
VL_UNCOPYABLE(VerilatedSerialize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VerilatedSerialize() {
|
VerilatedSerialize() {
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
@@ -54,7 +55,7 @@ public:
|
|||||||
}
|
}
|
||||||
virtual ~VerilatedSerialize() {
|
virtual ~VerilatedSerialize() {
|
||||||
close();
|
close();
|
||||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL);
|
||||||
}
|
}
|
||||||
// METHODS
|
// METHODS
|
||||||
bool isOpen() const { return m_isOpen; }
|
bool isOpen() const { return m_isOpen; }
|
||||||
@@ -65,20 +66,20 @@ public:
|
|||||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||||
while (size) {
|
while (size) {
|
||||||
bufferCheck();
|
bufferCheck();
|
||||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
size_t blk = size;
|
||||||
|
if (blk > bufferInsertSize()) blk = bufferInsertSize();
|
||||||
const vluint8_t* __restrict maxp = dp + blk;
|
const vluint8_t* __restrict maxp = dp + blk;
|
||||||
while (dp < maxp) *m_cp++ = *dp++;
|
for (; dp < maxp; *m_cp++ = *dp++) {}
|
||||||
size -= blk;
|
size -= blk;
|
||||||
}
|
}
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||||
// Flush the write buffer if there's not enough space left for new information
|
// Flush the write buffer if there's not enough space left for new information
|
||||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||||
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
if (VL_UNLIKELY(m_cp > (m_bufp + (bufferSize() - bufferInsertSize())))) flush();
|
||||||
flush();
|
|
||||||
}
|
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -107,6 +108,7 @@ protected:
|
|||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedDeserialize);
|
VL_UNCOPYABLE(VerilatedDeserialize);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VerilatedDeserialize() {
|
VerilatedDeserialize() {
|
||||||
m_isOpen = false;
|
m_isOpen = false;
|
||||||
@@ -116,7 +118,7 @@ public:
|
|||||||
}
|
}
|
||||||
virtual ~VerilatedDeserialize() {
|
virtual ~VerilatedDeserialize() {
|
||||||
close();
|
close();
|
||||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
if (m_bufp) VL_DO_CLEAR(delete m_bufp, m_bufp = NULL);
|
||||||
}
|
}
|
||||||
// METHODS
|
// METHODS
|
||||||
bool isOpen() const { return m_isOpen; }
|
bool isOpen() const { return m_isOpen; }
|
||||||
@@ -124,12 +126,13 @@ public:
|
|||||||
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
||||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||||
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||||
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
vluint8_t* __restrict dp = static_cast<vluint8_t* __restrict>(datap);
|
||||||
while (size) {
|
while (size) {
|
||||||
bufferCheck();
|
bufferCheck();
|
||||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
size_t blk = size;
|
||||||
|
if (blk > bufferInsertSize()) blk = bufferInsertSize();
|
||||||
const vluint8_t* __restrict maxp = dp + blk;
|
const vluint8_t* __restrict maxp = dp + blk;
|
||||||
while (dp < maxp) *dp++ = *m_cp++;
|
for (; dp < maxp; *dp++ = *m_cp++) {}
|
||||||
size -= blk;
|
size -= blk;
|
||||||
}
|
}
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
@@ -137,15 +140,15 @@ public:
|
|||||||
// Read a datum and compare with expected value
|
// Read a datum and compare with expected value
|
||||||
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||||
VerilatedDeserialize& readAssert(vluint64_t data) VL_MT_UNSAFE_ONE {
|
VerilatedDeserialize& readAssert(vluint64_t data) VL_MT_UNSAFE_ONE {
|
||||||
return readAssert(&data, sizeof(data)); }
|
return readAssert(&data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||||
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||||
// Flush the write buffer if there's not enough space left for new information
|
// Flush the write buffer if there's not enough space left for new information
|
||||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||||
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
if (VL_UNLIKELY((m_cp + bufferInsertSize()) > m_endp)) fill();
|
||||||
fill();
|
|
||||||
}
|
|
||||||
return *this; // For function chaining
|
return *this; // For function chaining
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -160,10 +163,12 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedSave() { m_fd = -1; }
|
VerilatedSave()
|
||||||
|
: m_fd(-1) {}
|
||||||
virtual ~VerilatedSave() VL_OVERRIDE { close(); }
|
virtual ~VerilatedSave() VL_OVERRIDE { close(); }
|
||||||
// METHODS
|
// METHODS
|
||||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
/// Open the file; call isOpen() to see if errors
|
||||||
|
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
|
||||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||||
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||||
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||||
@@ -179,11 +184,13 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedRestore() { m_fd = -1; }
|
VerilatedRestore()
|
||||||
|
: m_fd(-1) {}
|
||||||
virtual ~VerilatedRestore() VL_OVERRIDE { close(); }
|
virtual ~VerilatedRestore() VL_OVERRIDE { close(); }
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
/// Open the file; call isOpen() to see if errors
|
||||||
|
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
|
||||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||||
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||||
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {}
|
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {}
|
||||||
@@ -250,8 +257,8 @@ VerilatedSerialize& operator<<(VerilatedSerialize& os, VlAssocArray<T_Key, T_Val
|
|||||||
os << rhs.atDefault();
|
os << rhs.atDefault();
|
||||||
vluint32_t len = rhs.size();
|
vluint32_t len = rhs.size();
|
||||||
os << len;
|
os << len;
|
||||||
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = rhs.begin();
|
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = rhs.begin(); it != rhs.end();
|
||||||
it != rhs.end(); ++it) {
|
++it) {
|
||||||
T_Key index = it->first; // Copy to get around const_iterator
|
T_Key index = it->first; // Copy to get around const_iterator
|
||||||
T_Value value = it->second;
|
T_Value value = it->second;
|
||||||
os << index << value;
|
os << index << value;
|
||||||
|
|||||||
@@ -29,20 +29,31 @@
|
|||||||
|
|
||||||
#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
|
||||||
|
|
||||||
// See also V3Ast::VNumRange
|
// See also V3Ast::VNumRange
|
||||||
class VerilatedRange {
|
class VerilatedRange {
|
||||||
int m_left;
|
int m_left;
|
||||||
int m_right;
|
int m_right;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
friend class VerilatedVarProps;
|
friend class VerilatedVarProps;
|
||||||
friend class VerilatedScope;
|
friend class VerilatedScope;
|
||||||
VerilatedRange() : m_left(0), m_right(0) {}
|
VerilatedRange()
|
||||||
VerilatedRange(int left, int right) : m_left(left), m_right(right) {}
|
: m_left(0)
|
||||||
void init(int left, int right) { m_left=left; m_right=right; }
|
, m_right(0) {}
|
||||||
|
VerilatedRange(int left, int right)
|
||||||
|
: m_left(left)
|
||||||
|
, m_right(right) {}
|
||||||
|
void init(int left, int right) {
|
||||||
|
m_left = left;
|
||||||
|
m_right = right;
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~VerilatedRange() {}
|
~VerilatedRange() {}
|
||||||
int left() const { return m_left; }
|
int left() const { return m_left; }
|
||||||
@@ -50,7 +61,8 @@ public:
|
|||||||
int low() const { return (m_left < m_right) ? m_left : m_right; }
|
int low() const { return (m_left < m_right) ? m_left : m_right; }
|
||||||
int high() const { return (m_left > m_right) ? m_left : m_right; }
|
int high() const { return (m_left > m_right) ? m_left : m_right; }
|
||||||
int elements() const {
|
int elements() const {
|
||||||
return (VL_LIKELY(m_left>=m_right) ? (m_left-m_right+1) : (m_right-m_left+1)); }
|
return (VL_LIKELY(m_left >= m_right) ? (m_left - m_right + 1) : (m_right - m_left + 1));
|
||||||
|
}
|
||||||
int increment() const { return (m_left >= m_right) ? 1 : -1; }
|
int increment() const { return (m_left >= m_right) ? 1 : -1; }
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,71 +74,77 @@ class VerilatedVarProps {
|
|||||||
// TYPES
|
// TYPES
|
||||||
enum { MAGIC = 0xddc4f829 };
|
enum { MAGIC = 0xddc4f829 };
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
const vluint32_t m_magic; // Magic number
|
const vluint32_t m_magic; // Magic number
|
||||||
const VerilatedVarType m_vltype; // Data type
|
const VerilatedVarType m_vltype; // Data type
|
||||||
const VerilatedVarFlags m_vlflags; // Direction
|
const VerilatedVarFlags m_vlflags; // Direction
|
||||||
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;
|
||||||
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags,
|
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims)
|
||||||
int pdims, int udims)
|
: m_magic(MAGIC)
|
||||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(vlflags), m_pdims(pdims), m_udims(udims) {}
|
, m_vltype(vltype)
|
||||||
|
, m_vlflags(vlflags)
|
||||||
|
, m_pdims(pdims)
|
||||||
|
, m_udims(udims) {
|
||||||
|
initUnpacked(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class Unpacked {};
|
class Unpacked {};
|
||||||
// Without packed
|
// Without packed
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
||||||
: m_magic(MAGIC), m_vltype(vltype),
|
: m_magic(MAGIC)
|
||||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(0) { }
|
, m_vltype(vltype)
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||||
Unpacked, int u0l, int u0r)
|
, m_pdims(0)
|
||||||
: m_magic(MAGIC), m_vltype(vltype),
|
, m_udims(0) {}
|
||||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(1) {
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
|
||||||
m_unpacked[0].init(u0l, u0r); }
|
: m_magic(MAGIC)
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
, m_vltype(vltype)
|
||||||
Unpacked, int u0l, int u0r, int u1l, int u1r)
|
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||||
: m_magic(MAGIC), m_vltype(vltype),
|
, m_pdims(0)
|
||||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(2) {
|
, m_udims(udims) {
|
||||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); }
|
initUnpacked(ulims);
|
||||||
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 {};
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr)
|
||||||
Packed, int pl, int pr)
|
: m_magic(MAGIC)
|
||||||
: m_magic(MAGIC), m_vltype(vltype),
|
, m_vltype(vltype)
|
||||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(0), m_packed(pl,pr) { }
|
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
, m_pdims(1)
|
||||||
Packed, int pl, int pr,
|
, m_udims(0)
|
||||||
Unpacked, int u0l, int u0r)
|
, m_packed(pl, pr) {}
|
||||||
: m_magic(MAGIC), m_vltype(vltype),
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
|
||||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(1), m_packed(pl,pr) {
|
int udims, const int* ulims)
|
||||||
m_unpacked[0].init(u0l, u0r); }
|
: m_magic(MAGIC)
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
, m_vltype(vltype)
|
||||||
Packed, int pl, int pr,
|
, m_vlflags(VerilatedVarFlags(vlflags))
|
||||||
Unpacked, int u0l, int u0r, int u1l, int u1r)
|
, m_pdims(1)
|
||||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)),
|
, m_udims(udims)
|
||||||
m_pdims(1), m_udims(2), m_packed(pl,pr) {
|
, m_packed(pl, pr) {
|
||||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); }
|
initUnpacked(ulims);
|
||||||
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:
|
||||||
~VerilatedVarProps() {}
|
~VerilatedVarProps() {}
|
||||||
// METHODS
|
// METHODS
|
||||||
bool magicOk() const { return m_magic == MAGIC; }
|
bool magicOk() const { return m_magic == MAGIC; }
|
||||||
VerilatedVarType vltype() const { return m_vltype; }
|
VerilatedVarType vltype() const { return m_vltype; }
|
||||||
VerilatedVarFlags vldir() const {
|
VerilatedVarFlags vldir() const {
|
||||||
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR); }
|
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
|
||||||
|
}
|
||||||
vluint32_t entSize() const;
|
vluint32_t entSize() const;
|
||||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||||
/// DPI compatible C standard layout
|
/// DPI compatible C standard layout
|
||||||
@@ -137,28 +155,30 @@ public:
|
|||||||
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
||||||
// 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;
|
||||||
@@ -199,7 +219,8 @@ public:
|
|||||||
int elements(int dim) const { return m_propsp->elements(dim); }
|
int elements(int dim) const { return m_propsp->elements(dim); }
|
||||||
size_t totalSize() const { return m_propsp->totalSize(); }
|
size_t totalSize() const { return m_propsp->totalSize(); }
|
||||||
void* datapAdjustIndex(void* datap, int dim, int indx) const {
|
void* datapAdjustIndex(void* datap, int dim, int indx) const {
|
||||||
return m_propsp->datapAdjustIndex(datap, dim, indx); }
|
return m_propsp->datapAdjustIndex(datap, dim, indx);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//===========================================================================
|
//===========================================================================
|
||||||
@@ -213,10 +234,12 @@ class VerilatedVar : public VerilatedVarProps {
|
|||||||
protected:
|
protected:
|
||||||
friend class VerilatedScope;
|
friend class VerilatedScope;
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedVar(const char* namep, void* datap,
|
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||||
VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims)
|
VerilatedVarFlags vlflags, int dims)
|
||||||
: 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_namep(namep) {}
|
, m_datap(datap)
|
||||||
|
, m_namep(namep) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
~VerilatedVar() {}
|
~VerilatedVar() {}
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
|
|||||||
@@ -27,8 +27,8 @@ VL_THREAD_LOCAL VlThreadPool::ProfileTrace* VlThreadPool::t_profilep = NULL;
|
|||||||
// VlMTaskVertex
|
// VlMTaskVertex
|
||||||
|
|
||||||
VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount)
|
VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount)
|
||||||
: m_upstreamDepsDone(0),
|
: m_upstreamDepsDone(0)
|
||||||
m_upstreamDepCount(upstreamDepCount) {
|
, m_upstreamDepCount(upstreamDepCount) {
|
||||||
assert(atomic_is_lock_free(&m_upstreamDepsDone));
|
assert(atomic_is_lock_free(&m_upstreamDepsDone));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,7 +41,7 @@ VlWorkerThread::VlWorkerThread(VlThreadPool* poolp, bool profiling)
|
|||||||
, m_poolp(poolp)
|
, m_poolp(poolp)
|
||||||
, m_profiling(profiling)
|
, m_profiling(profiling)
|
||||||
, m_exiting(false)
|
, m_exiting(false)
|
||||||
// Must init this last -- after setting up fields that it might read:
|
// Must init this last -- after setting up fields that it might read:
|
||||||
, m_cthread(startWorker, this) {}
|
, m_cthread(startWorker, this) {}
|
||||||
|
|
||||||
VlWorkerThread::~VlWorkerThread() {
|
VlWorkerThread::~VlWorkerThread() {
|
||||||
@@ -52,21 +52,16 @@ VlWorkerThread::~VlWorkerThread() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VlWorkerThread::workerLoop() {
|
void VlWorkerThread::workerLoop() {
|
||||||
if (VL_UNLIKELY(m_profiling)) {
|
if (VL_UNLIKELY(m_profiling)) m_poolp->setupProfilingClientThread();
|
||||||
m_poolp->setupProfilingClientThread();
|
|
||||||
}
|
|
||||||
|
|
||||||
ExecRec work;
|
ExecRec work;
|
||||||
work.m_fnp = NULL;
|
work.m_fnp = NULL;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
if (VL_LIKELY(!work.m_fnp)) {
|
if (VL_LIKELY(!work.m_fnp)) dequeWork(&work);
|
||||||
dequeWork(&work);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Do this here, not above, to avoid a race with the destructor.
|
// Do this here, not above, to avoid a race with the destructor.
|
||||||
if (VL_UNLIKELY(m_exiting.load(std::memory_order_acquire)))
|
if (VL_UNLIKELY(m_exiting.load(std::memory_order_acquire))) break;
|
||||||
break;
|
|
||||||
|
|
||||||
if (VL_LIKELY(work.m_fnp)) {
|
if (VL_LIKELY(work.m_fnp)) {
|
||||||
work.m_fnp(work.m_evenCycle, work.m_sym);
|
work.m_fnp(work.m_evenCycle, work.m_sym);
|
||||||
@@ -74,14 +69,10 @@ void VlWorkerThread::workerLoop() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VL_UNLIKELY(m_profiling)) {
|
if (VL_UNLIKELY(m_profiling)) m_poolp->tearDownProfilingClientThread();
|
||||||
m_poolp->tearDownProfilingClientThread();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlWorkerThread::startWorker(VlWorkerThread* workerp) {
|
void VlWorkerThread::startWorker(VlWorkerThread* workerp) { workerp->workerLoop(); }
|
||||||
workerp->workerLoop();
|
|
||||||
}
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlThreadPool
|
// VlThreadPool
|
||||||
@@ -90,23 +81,22 @@ VlThreadPool::VlThreadPool(int nThreads, bool profiling)
|
|||||||
: m_profiling(profiling) {
|
: m_profiling(profiling) {
|
||||||
// --threads N passes nThreads=N-1, as the "main" threads counts as 1
|
// --threads N passes nThreads=N-1, as the "main" threads counts as 1
|
||||||
unsigned cpus = std::thread::hardware_concurrency();
|
unsigned cpus = std::thread::hardware_concurrency();
|
||||||
if (cpus < nThreads+1) {
|
if (cpus < nThreads + 1) {
|
||||||
static int warnedOnce = 0;
|
static int warnedOnce = 0;
|
||||||
if (!warnedOnce++) {
|
if (!warnedOnce++) {
|
||||||
VL_PRINTF_MT("%%Warning: System has %u CPUs but model Verilated with"
|
VL_PRINTF_MT("%%Warning: System has %u CPUs but model Verilated with"
|
||||||
" --threads %d; may run slow.\n", cpus, nThreads+1);
|
" --threads %d; may run slow.\n",
|
||||||
|
cpus, nThreads + 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Create'em
|
// Create'em
|
||||||
for (int i=0; i<nThreads; ++i) {
|
for (int i = 0; i < nThreads; ++i) {
|
||||||
m_workers.push_back(new VlWorkerThread(this, profiling));
|
m_workers.push_back(new VlWorkerThread(this, profiling));
|
||||||
}
|
}
|
||||||
// Set up a profile buffer for the current thread too -- on the
|
// Set up a profile buffer for the current thread too -- on the
|
||||||
// assumption that it's the same thread that calls eval and may be
|
// assumption that it's the same thread that calls eval and may be
|
||||||
// donated to run mtasks during the eval.
|
// donated to run mtasks during the eval.
|
||||||
if (VL_UNLIKELY(m_profiling)) {
|
if (VL_UNLIKELY(m_profiling)) setupProfilingClientThread();
|
||||||
setupProfilingClientThread();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VlThreadPool::~VlThreadPool() {
|
VlThreadPool::~VlThreadPool() {
|
||||||
@@ -114,9 +104,7 @@ VlThreadPool::~VlThreadPool() {
|
|||||||
// Each ~WorkerThread will wait for its thread to exit.
|
// Each ~WorkerThread will wait for its thread to exit.
|
||||||
delete m_workers[i];
|
delete m_workers[i];
|
||||||
}
|
}
|
||||||
if (VL_UNLIKELY(m_profiling)) {
|
if (VL_UNLIKELY(m_profiling)) tearDownProfilingClientThread();
|
||||||
tearDownProfilingClientThread();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VlThreadPool::tearDownProfilingClientThread() {
|
void VlThreadPool::tearDownProfilingClientThread() {
|
||||||
@@ -132,73 +120,65 @@ 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();
|
for (ProfileSet::iterator it = m_allProfiles.begin(); it != m_allProfiles.end(); ++it) {
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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");
|
||||||
if (VL_UNLIKELY(!fp)) {
|
if (VL_UNLIKELY(!fp)) {
|
||||||
VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable");
|
VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable");
|
||||||
|
// cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Perhaps merge with verilated_coverage output format, so can
|
// TODO Perhaps merge with verilated_coverage output format, so can
|
||||||
// have a common merging and reporting tool, etc.
|
// have a common merging and reporting tool, etc.
|
||||||
fprintf(fp, "VLPROFTHREAD 1.0 # Verilator thread profile dump version 1.0\n");
|
fprintf(fp, "VLPROFTHREAD 1.0 # Verilator thread profile dump version 1.0\n");
|
||||||
fprintf(fp, "VLPROF arg --threads %" VL_PRI64 "u\n",
|
fprintf(fp, "VLPROF arg --threads %" VL_PRI64 "u\n", vluint64_t(m_workers.size() + 1));
|
||||||
vluint64_t(m_workers.size()+1));
|
|
||||||
fprintf(fp, "VLPROF arg +verilator+prof+threads+start+%" VL_PRI64 "u\n",
|
fprintf(fp, "VLPROF arg +verilator+prof+threads+start+%" VL_PRI64 "u\n",
|
||||||
Verilated::profThreadsStart());
|
Verilated::profThreadsStart());
|
||||||
fprintf(fp, "VLPROF arg +verilator+prof+threads+window+%u\n",
|
fprintf(fp, "VLPROF arg +verilator+prof+threads+window+%u\n", Verilated::profThreadsWindow());
|
||||||
Verilated::profThreadsWindow());
|
fprintf(fp, "VLPROF stat yields %" VL_PRI64 "u\n", VlMTaskVertex::yields());
|
||||||
fprintf(fp, "VLPROF stat yields %" VL_PRI64 "u\n",
|
|
||||||
VlMTaskVertex::yields());
|
|
||||||
|
|
||||||
vluint32_t thread_id = 0;
|
vluint32_t thread_id = 0;
|
||||||
for (ProfileSet::const_iterator pit = m_allProfiles.begin();
|
for (ProfileSet::const_iterator pit = m_allProfiles.begin(); pit != m_allProfiles.end();
|
||||||
pit != m_allProfiles.end(); ++pit) {
|
++pit) {
|
||||||
++thread_id;
|
++thread_id;
|
||||||
|
|
||||||
bool printing = false; // False while in warmup phase
|
bool printing = false; // False while in warmup phase
|
||||||
for (ProfileTrace::const_iterator eit = (*pit)->begin();
|
for (ProfileTrace::const_iterator eit = (*pit)->begin(); eit != (*pit)->end(); ++eit) {
|
||||||
eit != (*pit)->end(); ++eit) {
|
|
||||||
switch (eit->m_type) {
|
switch (eit->m_type) {
|
||||||
case VlProfileRec::TYPE_BARRIER:
|
case VlProfileRec::TYPE_BARRIER: //
|
||||||
printing = true;
|
printing = true;
|
||||||
break;
|
break;
|
||||||
case VlProfileRec::TYPE_MTASK_RUN:
|
case VlProfileRec::TYPE_MTASK_RUN:
|
||||||
if (!printing) break;
|
if (!printing) break;
|
||||||
fprintf(fp, "VLPROF mtask %d"
|
fprintf(fp,
|
||||||
" start %" VL_PRI64"u end %" VL_PRI64"u elapsed %" VL_PRI64 "u"
|
"VLPROF mtask %d"
|
||||||
|
" start %" VL_PRI64 "u end %" VL_PRI64 "u elapsed %" VL_PRI64 "u"
|
||||||
" predict_time %u cpu %u on thread %u\n",
|
" predict_time %u cpu %u on thread %u\n",
|
||||||
eit->m_mtaskId,
|
eit->m_mtaskId, eit->m_startTime, eit->m_endTime,
|
||||||
eit->m_startTime,
|
(eit->m_endTime - eit->m_startTime), eit->m_predictTime, eit->m_cpu,
|
||||||
eit->m_endTime,
|
|
||||||
(eit->m_endTime - eit->m_startTime),
|
|
||||||
eit->m_predictTime,
|
|
||||||
eit->m_cpu,
|
|
||||||
thread_id);
|
thread_id);
|
||||||
break;
|
break;
|
||||||
default: assert(false); break; // LCOV_EXCL_LINE
|
default: assert(false); break; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fprintf(fp, "VLPROF stat ticks %" VL_PRI64 "u\n",
|
fprintf(fp, "VLPROF stat ticks %" VL_PRI64 "u\n", ticksElapsed);
|
||||||
ticksElapsed);
|
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,12 +25,15 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
#if defined(__linux)
|
#if defined(__linux)
|
||||||
#include <sched.h> // For sched_getcpu()
|
# include <sched.h> // For sched_getcpu()
|
||||||
#endif
|
#endif
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
# include <cpuid.h> // For __cpuid_count()
|
# include <cpuid.h> // For __cpuid_count()
|
||||||
#endif
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
// VlMTaskVertex and VlThreadpool will work with multiple symbol table types.
|
// VlMTaskVertex and VlThreadpool will work with multiple symbol table types.
|
||||||
// Since the type is opaque to VlMTaskVertex and VlThreadPool, represent it
|
// Since the type is opaque to VlMTaskVertex and VlThreadPool, represent it
|
||||||
@@ -115,10 +118,7 @@ public:
|
|||||||
class VlProfileRec {
|
class VlProfileRec {
|
||||||
protected:
|
protected:
|
||||||
friend class VlThreadPool;
|
friend class VlThreadPool;
|
||||||
enum VlProfileE {
|
enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER };
|
||||||
TYPE_MTASK_RUN,
|
|
||||||
TYPE_BARRIER
|
|
||||||
};
|
|
||||||
VlProfileE m_type; // Record type
|
VlProfileE m_type; // Record type
|
||||||
vluint32_t m_mtaskId; // Mtask we're logging
|
vluint32_t m_mtaskId; // Mtask we're logging
|
||||||
vluint32_t m_predictTime; // How long scheduler predicted would take
|
vluint32_t m_predictTime; // How long scheduler predicted would take
|
||||||
@@ -173,9 +173,14 @@ private:
|
|||||||
VlExecFnp m_fnp; // Function to execute
|
VlExecFnp m_fnp; // Function to execute
|
||||||
VlThrSymTab m_sym; // Symbol table to execute
|
VlThrSymTab m_sym; // Symbol table to execute
|
||||||
bool m_evenCycle; // Even/odd for flag alternation
|
bool m_evenCycle; // Even/odd for flag alternation
|
||||||
ExecRec() : m_fnp(NULL), m_sym(NULL), m_evenCycle(false) {}
|
ExecRec()
|
||||||
|
: m_fnp(NULL)
|
||||||
|
, m_sym(NULL)
|
||||||
|
, m_evenCycle(false) {}
|
||||||
ExecRec(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym)
|
ExecRec(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym)
|
||||||
: m_fnp(fnp), m_sym(sym), m_evenCycle(evenCycle) {}
|
: m_fnp(fnp)
|
||||||
|
, m_sym(sym)
|
||||||
|
, m_evenCycle(evenCycle) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
@@ -208,7 +213,7 @@ public:
|
|||||||
inline void dequeWork(ExecRec* workp) {
|
inline void dequeWork(ExecRec* workp) {
|
||||||
// Spin for a while, waiting for new data
|
// Spin for a while, waiting for new data
|
||||||
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) {
|
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { //
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
VL_CPU_RELAX();
|
VL_CPU_RELAX();
|
||||||
@@ -229,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;
|
||||||
@@ -284,6 +289,7 @@ public:
|
|||||||
// this once to setup profiling state:
|
// this once to setup profiling state:
|
||||||
void setupProfilingClientThread();
|
void setupProfilingClientThread();
|
||||||
void tearDownProfilingClientThread();
|
void tearDownProfilingClientThread();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VL_UNCOPYABLE(VlThreadPool);
|
VL_UNCOPYABLE(VlThreadPool);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,398 @@
|
|||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// THIS MODULE IS PUBLICLY LICENSED
|
||||||
|
//
|
||||||
|
// Copyright 2001-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
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Tracing functionality common to all formats
|
||||||
|
///
|
||||||
|
//=============================================================================
|
||||||
|
// SPDIFF_OFF
|
||||||
|
|
||||||
|
#ifndef _VERILATED_TRACE_H_
|
||||||
|
#define _VERILATED_TRACE_H_ 1
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#include "verilated.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
# include <condition_variable>
|
||||||
|
# include <deque>
|
||||||
|
# include <thread>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
//=============================================================================
|
||||||
|
// Threaded tracing
|
||||||
|
|
||||||
|
// A simple synchronized first in first out queue
|
||||||
|
template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
|
||||||
|
private:
|
||||||
|
VerilatedMutex m_mutex; // Protects m_queue
|
||||||
|
std::condition_variable_any m_cv;
|
||||||
|
std::deque<T> m_queue VL_GUARDED_BY(m_mutex);
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Put an element at the back of the queue
|
||||||
|
void put(T value) {
|
||||||
|
VerilatedLockGuard lock(m_mutex);
|
||||||
|
m_queue.push_back(value);
|
||||||
|
m_cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put an element at the front of the queue
|
||||||
|
void put_front(T value) {
|
||||||
|
VerilatedLockGuard lock(m_mutex);
|
||||||
|
m_queue.push_front(value);
|
||||||
|
m_cv.notify_one();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get an element from the front of the queue. Blocks if none available
|
||||||
|
T get() {
|
||||||
|
VerilatedLockGuard lock(m_mutex);
|
||||||
|
m_cv.wait(lock, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); });
|
||||||
|
assert(!m_queue.empty());
|
||||||
|
T value = m_queue.front();
|
||||||
|
m_queue.pop_front();
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Non blocking get
|
||||||
|
bool tryGet(T& result) {
|
||||||
|
const VerilatedLockGuard lockGuard(m_mutex);
|
||||||
|
if (m_queue.empty()) { return false; }
|
||||||
|
result = m_queue.front();
|
||||||
|
m_queue.pop_front();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Commands used by thread tracing. Anonymous enum in class, as we want
|
||||||
|
// it scoped, but we also want the automatic conversion to integer types.
|
||||||
|
class VerilatedTraceCommand {
|
||||||
|
public:
|
||||||
|
// These must all fit in 4 bit at the moment, as the tracing routines
|
||||||
|
// pack parameters in the top bits.
|
||||||
|
enum {
|
||||||
|
CHG_BIT_0 = 0x0,
|
||||||
|
CHG_BIT_1 = 0x1,
|
||||||
|
CHG_CDATA = 0x2,
|
||||||
|
CHG_SDATA = 0x3,
|
||||||
|
CHG_IDATA = 0x4,
|
||||||
|
CHG_QDATA = 0x5,
|
||||||
|
CHG_WDATA = 0x6,
|
||||||
|
CHG_DOUBLE = 0x8,
|
||||||
|
// TODO: full..
|
||||||
|
TIME_CHANGE = 0xd,
|
||||||
|
END = 0xe, // End of buffer
|
||||||
|
SHUTDOWN = 0xf // Shutdown worker thread, also marks end of buffer
|
||||||
|
};
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VerilatedTrace
|
||||||
|
|
||||||
|
// VerilatedTrace uses F-bounded polymorphism to access duck-typed
|
||||||
|
// implementations in the format specific derived class, which must be passed
|
||||||
|
// as the type parameter T_Derived
|
||||||
|
template <class T_Derived> class VerilatedTrace {
|
||||||
|
public:
|
||||||
|
//=========================================================================
|
||||||
|
// Generic tracing internals
|
||||||
|
|
||||||
|
typedef void (*initCb_t)(void*, T_Derived*, uint32_t); // Type of init callbacks
|
||||||
|
typedef void (*dumpCb_t)(void*, T_Derived*); // Type of all but init callbacks
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct CallbackRecord {
|
||||||
|
// Note: would make these fields const, but some old STL implementations
|
||||||
|
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
|
||||||
|
// assignment operator on inserting into collections, so they don't work
|
||||||
|
// with const fields...
|
||||||
|
union {
|
||||||
|
initCb_t m_initCb; // The callback function
|
||||||
|
dumpCb_t m_dumpCb; // The callback function
|
||||||
|
};
|
||||||
|
void* m_userp; // The user pointer to pass to the callback (the symbol table)
|
||||||
|
CallbackRecord(initCb_t cb, void* userp)
|
||||||
|
: m_initCb(cb)
|
||||||
|
, m_userp(userp) {}
|
||||||
|
CallbackRecord(dumpCb_t cb, void* userp)
|
||||||
|
: m_dumpCb(cb)
|
||||||
|
, m_userp(userp) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
vluint32_t* m_sigs_oldvalp; ///< Old value store
|
||||||
|
vluint64_t m_timeLastDump; ///< Last time we did a dump
|
||||||
|
std::vector<CallbackRecord> m_initCbs; ///< Routines to initialize traciong
|
||||||
|
std::vector<CallbackRecord> m_fullCbs; ///< Routines to perform full dump
|
||||||
|
std::vector<CallbackRecord> m_chgCbs; ///< Routines to perform incremental dump
|
||||||
|
std::vector<CallbackRecord> m_cleanupCbs; ///< Routines to call at the end of dump
|
||||||
|
bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump'
|
||||||
|
vluint32_t m_nextCode; ///< Next code number to assign
|
||||||
|
vluint32_t m_numSignals; ///< Number of distinct signals
|
||||||
|
vluint32_t m_maxBits; ///< Number of bits in the widest signal
|
||||||
|
std::string m_moduleName; ///< Name of module being trace initialized now
|
||||||
|
char m_scopeEscape;
|
||||||
|
double m_timeRes; ///< Time resolution (ns/ms etc)
|
||||||
|
double m_timeUnit; ///< Time units (ns/ms etc)
|
||||||
|
|
||||||
|
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord& cbRec);
|
||||||
|
|
||||||
|
// Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->'
|
||||||
|
// to access duck-typed functions to avoid a virtual function call.
|
||||||
|
T_Derived* self() { return static_cast<T_Derived*>(this); }
|
||||||
|
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
// Number of total trace buffers that have been allocated
|
||||||
|
vluint32_t m_numTraceBuffers;
|
||||||
|
|
||||||
|
// Size of trace buffers
|
||||||
|
size_t m_traceBufferSize;
|
||||||
|
|
||||||
|
// Buffers handed to worker for processing
|
||||||
|
VerilatedThreadQueue<vluint32_t*> m_buffersToWorker;
|
||||||
|
// Buffers returned from worker after processing
|
||||||
|
VerilatedThreadQueue<vluint32_t*> m_buffersFromWorker;
|
||||||
|
|
||||||
|
// Get a new trace buffer that can be populated. May block if none available
|
||||||
|
vluint32_t* getTraceBuffer();
|
||||||
|
|
||||||
|
// Write pointer into current buffer
|
||||||
|
vluint32_t* m_traceBufferWritep;
|
||||||
|
|
||||||
|
// End of trace buffer
|
||||||
|
vluint32_t* m_traceBufferEndp;
|
||||||
|
|
||||||
|
// The worker thread itself
|
||||||
|
std::unique_ptr<std::thread> m_workerThread;
|
||||||
|
|
||||||
|
// The function executed by the worker thread
|
||||||
|
void workerThreadMain();
|
||||||
|
|
||||||
|
// Wait until given buffer is placed in m_buffersFromWorker
|
||||||
|
void waitForBuffer(const vluint32_t* bufferp);
|
||||||
|
|
||||||
|
// Shut down and join worker, if it's running, otherwise do nothing
|
||||||
|
void shutdownWorker();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// CONSTRUCTORS
|
||||||
|
VL_UNCOPYABLE(VerilatedTrace);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//=========================================================================
|
||||||
|
// Internals available to format specific implementations
|
||||||
|
|
||||||
|
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||||
|
|
||||||
|
vluint32_t nextCode() const { return m_nextCode; }
|
||||||
|
vluint32_t numSignals() const { return m_numSignals; }
|
||||||
|
vluint32_t maxBits() const { return m_maxBits; }
|
||||||
|
const std::string& moduleName() const { return m_moduleName; }
|
||||||
|
void fullDump(bool value) { m_fullDump = value; }
|
||||||
|
vluint64_t timeLastDump() { return m_timeLastDump; }
|
||||||
|
|
||||||
|
double timeRes() const { return m_timeRes; }
|
||||||
|
double timeUnit() const { return m_timeUnit; }
|
||||||
|
std::string timeResStr() const;
|
||||||
|
std::string timeUnitStr() const;
|
||||||
|
|
||||||
|
void traceInit() VL_MT_UNSAFE;
|
||||||
|
|
||||||
|
void declCode(vluint32_t code, vluint32_t bits, bool tri);
|
||||||
|
|
||||||
|
/// Is this an escape?
|
||||||
|
bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; }
|
||||||
|
/// Character that splits scopes. Note whitespace are ALWAYS escapes.
|
||||||
|
char scopeEscape() { return m_scopeEscape; }
|
||||||
|
|
||||||
|
void close();
|
||||||
|
void flush();
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Virtual functions to be provided by the format specific implementation
|
||||||
|
|
||||||
|
// Called when the trace moves forward to a new time point
|
||||||
|
virtual void emitTimeChange(vluint64_t timeui) = 0;
|
||||||
|
|
||||||
|
// These hooks are called before a full or change based dump is produced.
|
||||||
|
// The return value indicates whether to proceed with the dump.
|
||||||
|
virtual bool preFullDump() = 0;
|
||||||
|
virtual bool preChangeDump() = 0;
|
||||||
|
|
||||||
|
public:
|
||||||
|
//=========================================================================
|
||||||
|
// External interface to client code
|
||||||
|
|
||||||
|
explicit VerilatedTrace();
|
||||||
|
~VerilatedTrace();
|
||||||
|
|
||||||
|
// Set time units (s/ms, defaults to ns)
|
||||||
|
void set_time_unit(const char* unitp);
|
||||||
|
void set_time_unit(const std::string& unit);
|
||||||
|
// Set time resolution (s/ms, defaults to ns)
|
||||||
|
void set_time_resolution(const char* unitp);
|
||||||
|
void set_time_resolution(const std::string& unit);
|
||||||
|
|
||||||
|
// Call
|
||||||
|
void dump(vluint64_t timeui);
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Non-hot path internal interface to Verilator generated 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 module(const std::string& name) VL_MT_UNSAFE_ONE {
|
||||||
|
m_assertOne.check();
|
||||||
|
m_moduleName = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Hot path internal interface to Verilator generated code
|
||||||
|
|
||||||
|
// Implementation note: We rely on the following duck-typed implementations
|
||||||
|
// in the derived class T_Derived. These emit* functions record a format
|
||||||
|
// specific trace entry. Normally one would use pure virtual functions for
|
||||||
|
// these here, but we cannot afford dynamic dispatch for calling these as
|
||||||
|
// this is very hot code during tracing.
|
||||||
|
|
||||||
|
// duck-typed void emitBit(vluint32_t code, CData newval) = 0;
|
||||||
|
// duck-typed void emitCData(vluint32_t code, CData newval, int bits) = 0;
|
||||||
|
// duck-typed void emitSData(vluint32_t code, SData 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 emitWData(vluint32_t code, const WData* newvalp, int bits) = 0;
|
||||||
|
// duck-typed void emitDouble(vluint32_t code, double newval) = 0;
|
||||||
|
|
||||||
|
vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; }
|
||||||
|
|
||||||
|
// Write to previous value buffer value and emit trace entry.
|
||||||
|
void fullBit(vluint32_t* oldp, CData newval);
|
||||||
|
void fullCData(vluint32_t* oldp, CData newval, int bits);
|
||||||
|
void fullSData(vluint32_t* oldp, SData newval, int bits);
|
||||||
|
void fullIData(vluint32_t* oldp, IData newval, int bits);
|
||||||
|
void fullQData(vluint32_t* oldp, QData newval, int bits);
|
||||||
|
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits);
|
||||||
|
void fullDouble(vluint32_t* oldp, double newval);
|
||||||
|
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
// Threaded tracing. Just dump everything in the trace buffer
|
||||||
|
inline void chgBit(vluint32_t code, CData newval) {
|
||||||
|
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_BIT_0 | newval;
|
||||||
|
m_traceBufferWritep[1] = code;
|
||||||
|
m_traceBufferWritep += 2;
|
||||||
|
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||||
|
}
|
||||||
|
inline void chgCData(vluint32_t code, CData newval, int bits) {
|
||||||
|
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_CDATA;
|
||||||
|
m_traceBufferWritep[1] = code;
|
||||||
|
m_traceBufferWritep[2] = newval;
|
||||||
|
m_traceBufferWritep += 3;
|
||||||
|
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||||
|
}
|
||||||
|
inline void chgSData(vluint32_t code, SData newval, int bits) {
|
||||||
|
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_SDATA;
|
||||||
|
m_traceBufferWritep[1] = code;
|
||||||
|
m_traceBufferWritep[2] = newval;
|
||||||
|
m_traceBufferWritep += 3;
|
||||||
|
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||||
|
}
|
||||||
|
inline void chgIData(vluint32_t code, IData newval, int bits) {
|
||||||
|
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_IDATA;
|
||||||
|
m_traceBufferWritep[1] = code;
|
||||||
|
m_traceBufferWritep[2] = newval;
|
||||||
|
m_traceBufferWritep += 3;
|
||||||
|
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||||
|
}
|
||||||
|
inline void chgQData(vluint32_t code, QData newval, int bits) {
|
||||||
|
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_QDATA;
|
||||||
|
m_traceBufferWritep[1] = code;
|
||||||
|
*reinterpret_cast<QData*>(m_traceBufferWritep + 2) = newval;
|
||||||
|
m_traceBufferWritep += 4;
|
||||||
|
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||||
|
}
|
||||||
|
inline void chgWData(vluint32_t code, const WData* newvalp, int bits) {
|
||||||
|
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_WDATA;
|
||||||
|
m_traceBufferWritep[1] = code;
|
||||||
|
m_traceBufferWritep += 2;
|
||||||
|
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; }
|
||||||
|
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||||
|
}
|
||||||
|
inline void chgDouble(vluint32_t code, double newval) {
|
||||||
|
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE;
|
||||||
|
m_traceBufferWritep[1] = code;
|
||||||
|
// cppcheck-suppress invalidPointerCast
|
||||||
|
*reinterpret_cast<double*>(m_traceBufferWritep + 2) = newval;
|
||||||
|
m_traceBufferWritep += 4;
|
||||||
|
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||||
|
}
|
||||||
|
|
||||||
|
#define CHG(name) chg##name##Impl
|
||||||
|
#else
|
||||||
|
#define CHG(name) chg##name
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// In non-threaded mode, these are called directly by the trace callbacks,
|
||||||
|
// and are called chg*. In threaded mode, they are called by the worker
|
||||||
|
// thread and are called chg*Impl
|
||||||
|
|
||||||
|
// Check previous dumped value of signal. If changed, then emit trace entry
|
||||||
|
inline void CHG(Bit)(vluint32_t* oldp, CData newval) {
|
||||||
|
const vluint32_t diff = *oldp ^ newval;
|
||||||
|
if (VL_UNLIKELY(diff)) fullBit(oldp, newval);
|
||||||
|
}
|
||||||
|
inline void CHG(CData)(vluint32_t* oldp, CData newval, int bits) {
|
||||||
|
const vluint32_t diff = *oldp ^ newval;
|
||||||
|
if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits);
|
||||||
|
}
|
||||||
|
inline void CHG(SData)(vluint32_t* oldp, SData newval, int bits) {
|
||||||
|
const vluint32_t diff = *oldp ^ newval;
|
||||||
|
if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits);
|
||||||
|
}
|
||||||
|
inline void CHG(IData)(vluint32_t* oldp, IData newval, int bits) {
|
||||||
|
const vluint32_t diff = *oldp ^ newval;
|
||||||
|
if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits);
|
||||||
|
}
|
||||||
|
inline void CHG(QData)(vluint32_t* oldp, QData newval, int bits) {
|
||||||
|
const vluint64_t diff = *reinterpret_cast<QData*>(oldp) ^ newval;
|
||||||
|
if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits);
|
||||||
|
}
|
||||||
|
inline void CHG(WData)(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||||
|
for (int i = 0; i < (bits + 31) / 32; ++i) {
|
||||||
|
if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) {
|
||||||
|
fullWData(oldp, newvalp, bits);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inline void CHG(Double)(vluint32_t* oldp, double newval) {
|
||||||
|
// cppcheck-suppress invalidPointerCast
|
||||||
|
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef CHG
|
||||||
|
};
|
||||||
|
#endif // guard
|
||||||
@@ -0,0 +1,622 @@
|
|||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//=============================================================================
|
||||||
|
//
|
||||||
|
// THIS MODULE IS PUBLICLY LICENSED
|
||||||
|
//
|
||||||
|
// Copyright 2001-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
|
||||||
|
//
|
||||||
|
//=============================================================================
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Implementation of tracing functionality common to all trace formats
|
||||||
|
///
|
||||||
|
//=============================================================================
|
||||||
|
// SPDIFF_OFF
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
|
||||||
|
#ifndef VL_DERIVED_T
|
||||||
|
# error "This file should be included in trace format implementations"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "verilated_intrinsics.h"
|
||||||
|
#include "verilated_trace.h"
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
# include <iostream>
|
||||||
|
# define VL_TRACE_THREAD_DEBUG(msg) std::cout << "TRACE THREAD: " << msg << std::endl
|
||||||
|
#else
|
||||||
|
# define VL_TRACE_THREAD_DEBUG(msg)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Static utility functions
|
||||||
|
|
||||||
|
static double timescaleToDouble(const char* unitp) {
|
||||||
|
char* endp = NULL;
|
||||||
|
double value = strtod(unitp, &endp);
|
||||||
|
// On error so we allow just "ns" to return 1e-9.
|
||||||
|
if (value == 0.0 && endp == unitp) value = 1;
|
||||||
|
unitp = endp;
|
||||||
|
for (; *unitp && isspace(*unitp); unitp++) {}
|
||||||
|
switch (*unitp) {
|
||||||
|
case 's': value *= 1e1; break;
|
||||||
|
case 'm': value *= 1e-3; break;
|
||||||
|
case 'u': value *= 1e-6; break;
|
||||||
|
case 'n': value *= 1e-9; break;
|
||||||
|
case 'p': value *= 1e-12; break;
|
||||||
|
case 'f': value *= 1e-15; break;
|
||||||
|
case 'a': value *= 1e-18; break;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string doubleToTimescale(double value) {
|
||||||
|
const char* suffixp = "s";
|
||||||
|
// clang-format off
|
||||||
|
if (value >= 1e0) { suffixp = "s"; value *= 1e0; }
|
||||||
|
else if (value >= 1e-3 ) { suffixp = "ms"; value *= 1e3; }
|
||||||
|
else if (value >= 1e-6 ) { suffixp = "us"; value *= 1e6; }
|
||||||
|
else if (value >= 1e-9 ) { suffixp = "ns"; value *= 1e9; }
|
||||||
|
else if (value >= 1e-12) { suffixp = "ps"; value *= 1e12; }
|
||||||
|
else if (value >= 1e-15) { suffixp = "fs"; value *= 1e15; }
|
||||||
|
else if (value >= 1e-18) { suffixp = "as"; value *= 1e18; }
|
||||||
|
// clang-format on
|
||||||
|
char valuestr[100];
|
||||||
|
sprintf(valuestr, "%3.0f%s", value, suffixp);
|
||||||
|
return valuestr; // Gets converted to string, so no ref to stack
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
//=========================================================================
|
||||||
|
// Buffer management
|
||||||
|
|
||||||
|
template <> vluint32_t* VerilatedTrace<VL_DERIVED_T>::getTraceBuffer() {
|
||||||
|
vluint32_t* bufferp;
|
||||||
|
// Some jitter is expected, so some number of alternative trace buffers are
|
||||||
|
// required, but don't allocate more than 8 buffers.
|
||||||
|
if (m_numTraceBuffers < 8) {
|
||||||
|
// Allocate a new buffer if none is available
|
||||||
|
if (!m_buffersFromWorker.tryGet(bufferp)) {
|
||||||
|
++m_numTraceBuffers;
|
||||||
|
// Note: over allocate a bit so pointer comparison is well defined
|
||||||
|
// if we overflow only by a small amount
|
||||||
|
bufferp = new vluint32_t[m_traceBufferSize + 16];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Block until a buffer becomes available
|
||||||
|
bufferp = m_buffersFromWorker.get();
|
||||||
|
}
|
||||||
|
return bufferp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::waitForBuffer(const vluint32_t* buffp) {
|
||||||
|
// Slow path code only called on flush/shutdown, so use a simple algorithm.
|
||||||
|
// Collect buffers from worker and stash them until we get the one we want.
|
||||||
|
std::deque<vluint32_t*> stash;
|
||||||
|
do { stash.push_back(m_buffersFromWorker.get()); } while (stash.back() != buffp);
|
||||||
|
// Now put them back in the queue, in the original order.
|
||||||
|
while (!stash.empty()) {
|
||||||
|
m_buffersFromWorker.put_front(stash.back());
|
||||||
|
stash.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Worker thread
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
|
||||||
|
bool shutdown = false;
|
||||||
|
|
||||||
|
do {
|
||||||
|
vluint32_t* const bufferp = m_buffersToWorker.get();
|
||||||
|
|
||||||
|
VL_TRACE_THREAD_DEBUG("");
|
||||||
|
VL_TRACE_THREAD_DEBUG("Got buffer: " << bufferp);
|
||||||
|
|
||||||
|
const vluint32_t* readp = bufferp;
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const vluint32_t cmd = readp[0];
|
||||||
|
const vluint32_t top = cmd >> 4;
|
||||||
|
// Always set this up, as it is almost always needed
|
||||||
|
vluint32_t* const oldp = m_sigs_oldvalp + readp[1];
|
||||||
|
// Note this increment needs to be undone on commands which do not
|
||||||
|
// actually contain a code, but those are the rare cases.
|
||||||
|
readp += 2;
|
||||||
|
|
||||||
|
switch (cmd & 0xF) {
|
||||||
|
//===
|
||||||
|
// CHG_* commands
|
||||||
|
case VerilatedTraceCommand::CHG_BIT_0:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command CHG_BIT_0 " << top);
|
||||||
|
chgBitImpl(oldp, 0);
|
||||||
|
continue;
|
||||||
|
case VerilatedTraceCommand::CHG_BIT_1:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command CHG_BIT_1 " << top);
|
||||||
|
chgBitImpl(oldp, 1);
|
||||||
|
continue;
|
||||||
|
case VerilatedTraceCommand::CHG_CDATA:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command CHG_CDATA " << top);
|
||||||
|
// Bits stored in bottom byte of command
|
||||||
|
chgCDataImpl(oldp, *readp, top);
|
||||||
|
readp += 1;
|
||||||
|
continue;
|
||||||
|
case VerilatedTraceCommand::CHG_SDATA:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command CHG_SDATA " << top);
|
||||||
|
// Bits stored in bottom byte of command
|
||||||
|
chgSDataImpl(oldp, *readp, top);
|
||||||
|
readp += 1;
|
||||||
|
continue;
|
||||||
|
case VerilatedTraceCommand::CHG_IDATA:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command CHG_IDATA " << top);
|
||||||
|
// Bits stored in bottom byte of command
|
||||||
|
chgIDataImpl(oldp, *readp, top);
|
||||||
|
readp += 1;
|
||||||
|
continue;
|
||||||
|
case VerilatedTraceCommand::CHG_QDATA:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command CHG_QDATA " << top);
|
||||||
|
// Bits stored in bottom byte of command
|
||||||
|
chgQDataImpl(oldp, *reinterpret_cast<const QData*>(readp), top);
|
||||||
|
readp += 2;
|
||||||
|
continue;
|
||||||
|
case VerilatedTraceCommand::CHG_WDATA:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command CHG_WDATA " << top);
|
||||||
|
chgWDataImpl(oldp, readp, top);
|
||||||
|
readp += VL_WORDS_I(top);
|
||||||
|
continue;
|
||||||
|
case VerilatedTraceCommand::CHG_DOUBLE:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top);
|
||||||
|
chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
|
||||||
|
readp += 2;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//===
|
||||||
|
// Rare commands
|
||||||
|
case VerilatedTraceCommand::TIME_CHANGE:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command TIME_CHANGE " << top);
|
||||||
|
readp -= 1; // No code in this command, undo increment
|
||||||
|
emitTimeChange(*reinterpret_cast<const vluint64_t*>(readp));
|
||||||
|
readp += 2;
|
||||||
|
continue;
|
||||||
|
|
||||||
|
//===
|
||||||
|
// Commands ending this buffer
|
||||||
|
case VerilatedTraceCommand::END: VL_TRACE_THREAD_DEBUG("Command END"); break;
|
||||||
|
case VerilatedTraceCommand::SHUTDOWN:
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command SHUTDOWN");
|
||||||
|
shutdown = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
//===
|
||||||
|
// Unknown command
|
||||||
|
default: { // LCOV_EXCL_START
|
||||||
|
VL_TRACE_THREAD_DEBUG("Command UNKNOWN");
|
||||||
|
VL_PRINTF_MT("Trace command: 0x%08x\n", cmd);
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command");
|
||||||
|
break;
|
||||||
|
} // LCOV_EXCL_STOP
|
||||||
|
}
|
||||||
|
|
||||||
|
// The above switch will execute 'continue' when necessary,
|
||||||
|
// so if we ever reach here, we are done with the buffer.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
VL_TRACE_THREAD_DEBUG("Returning buffer");
|
||||||
|
|
||||||
|
// Return buffer
|
||||||
|
m_buffersFromWorker.put(bufferp);
|
||||||
|
} while (VL_LIKELY(!shutdown));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::shutdownWorker() {
|
||||||
|
// If the worker thread is not running, done..
|
||||||
|
if (!m_workerThread) return;
|
||||||
|
|
||||||
|
// Hand an buffer with a shutdown command to the worker thread
|
||||||
|
vluint32_t* const bufferp = getTraceBuffer();
|
||||||
|
bufferp[0] = VerilatedTraceCommand::SHUTDOWN;
|
||||||
|
m_buffersToWorker.put(bufferp);
|
||||||
|
// Wait for it to return
|
||||||
|
waitForBuffer(bufferp);
|
||||||
|
// Join the thread and delete it
|
||||||
|
m_workerThread->join();
|
||||||
|
m_workerThread.reset(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Life cycle
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::close() {
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
shutdownWorker();
|
||||||
|
while (m_numTraceBuffers) {
|
||||||
|
delete[] m_buffersFromWorker.get();
|
||||||
|
m_numTraceBuffers--;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::flush() {
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
// Hand an empty buffer to the worker thread
|
||||||
|
vluint32_t* const bufferp = getTraceBuffer();
|
||||||
|
*bufferp = VerilatedTraceCommand::END;
|
||||||
|
m_buffersToWorker.put(bufferp);
|
||||||
|
// Wait for it to be returned. As the processing is in-order,
|
||||||
|
// this ensures all previous buffers have been processed.
|
||||||
|
waitForBuffer(bufferp);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VerilatedTrace
|
||||||
|
|
||||||
|
template <>
|
||||||
|
VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
|
||||||
|
: m_sigs_oldvalp(NULL)
|
||||||
|
, m_timeLastDump(0)
|
||||||
|
, m_fullDump(true)
|
||||||
|
, m_nextCode(0)
|
||||||
|
, m_numSignals(0)
|
||||||
|
, m_maxBits(0)
|
||||||
|
, m_scopeEscape('.')
|
||||||
|
, m_timeRes(1e-9)
|
||||||
|
, m_timeUnit(1e-9)
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
, m_numTraceBuffers(0)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
set_time_unit(Verilated::timeunitString());
|
||||||
|
set_time_resolution(Verilated::timeprecisionString());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
|
||||||
|
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = NULL);
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
close();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Internals available to format specific implementations
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
|
||||||
|
m_assertOne.check();
|
||||||
|
|
||||||
|
// Note: It is possible to re-open a trace file (VCD in particular),
|
||||||
|
// so we must reset the next code here, but it must have the same number
|
||||||
|
// of codes on re-open
|
||||||
|
const vluint32_t expectedCodes = nextCode();
|
||||||
|
m_nextCode = 1;
|
||||||
|
m_numSignals = 0;
|
||||||
|
m_maxBits = 0;
|
||||||
|
|
||||||
|
// Call all initialize callbacks, which will:
|
||||||
|
// - Call decl* for each signal
|
||||||
|
// - Store the base code
|
||||||
|
for (vluint32_t i = 0; i < m_initCbs.size(); ++i) {
|
||||||
|
const CallbackRecord& cbr = m_initCbs[i];
|
||||||
|
cbr.m_initCb(cbr.m_userp, self(), nextCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expectedCodes && nextCode() != expectedCodes) {
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||||
|
"Reopening trace file with different number of signals");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now that we know the number of codes, allocate space for the buffer
|
||||||
|
// holding previous signal values.
|
||||||
|
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()];
|
||||||
|
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
// 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
|
||||||
|
// above have been run, plus up to 2 more words of metadata per signal,
|
||||||
|
// plus fixed overhead of 1 for a termination flag and 3 for a time stamp
|
||||||
|
// update.
|
||||||
|
m_traceBufferSize = nextCode() + numSignals() * 2 + 4;
|
||||||
|
|
||||||
|
// Start the worker thread
|
||||||
|
m_workerThread.reset(new std::thread(&VerilatedTrace<VL_DERIVED_T>::workerThreadMain, this));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void VerilatedTrace<VL_DERIVED_T>::declCode(vluint32_t code, vluint32_t bits, bool tri) {
|
||||||
|
if (!code) {
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal");
|
||||||
|
}
|
||||||
|
// Note: The tri-state flag is not used by Verilator, but is here for
|
||||||
|
// compatibility with some foreign code.
|
||||||
|
int codesNeeded = VL_WORDS_I(bits);
|
||||||
|
if (tri) codesNeeded *= 2;
|
||||||
|
m_nextCode = std::max(m_nextCode, code + codesNeeded);
|
||||||
|
++m_numSignals;
|
||||||
|
m_maxBits = std::max(m_maxBits, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Internals available to format specific implementations
|
||||||
|
|
||||||
|
template <> std::string VerilatedTrace<VL_DERIVED_T>::timeResStr() const {
|
||||||
|
return doubleToTimescale(m_timeRes);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> std::string VerilatedTrace<VL_DERIVED_T>::timeUnitStr() const {
|
||||||
|
return doubleToTimescale(m_timeUnit);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// External interface to client code
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::set_time_unit(const char* unitp) {
|
||||||
|
m_timeUnit = timescaleToDouble(unitp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::set_time_unit(const std::string& unit) {
|
||||||
|
set_time_unit(unit.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::set_time_resolution(const char* unitp) {
|
||||||
|
m_timeRes = timescaleToDouble(unitp);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::set_time_resolution(const std::string& unit) {
|
||||||
|
set_time_resolution(unit.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
|
||||||
|
m_assertOne.check();
|
||||||
|
if (VL_UNCOVERABLE(m_timeLastDump && timeui <= m_timeLastDump)) { // LCOV_EXCL_START
|
||||||
|
VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64
|
||||||
|
"u, dump call ignored\n",
|
||||||
|
m_timeLastDump, timeui);
|
||||||
|
return;
|
||||||
|
} // LCOV_EXCL_STOP
|
||||||
|
m_timeLastDump = timeui;
|
||||||
|
|
||||||
|
Verilated::quiesce();
|
||||||
|
|
||||||
|
// Call hook for format specific behaviour
|
||||||
|
if (VL_UNLIKELY(m_fullDump)) {
|
||||||
|
if (!preFullDump()) return;
|
||||||
|
} else {
|
||||||
|
if (!preChangeDump()) return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
// Currently only incremental dumps run on the worker thread
|
||||||
|
vluint32_t* bufferp = nullptr;
|
||||||
|
if (VL_LIKELY(!m_fullDump)) {
|
||||||
|
// Get the trace buffer we are about to fill
|
||||||
|
bufferp = getTraceBuffer();
|
||||||
|
m_traceBufferWritep = bufferp;
|
||||||
|
m_traceBufferEndp = bufferp + m_traceBufferSize;
|
||||||
|
|
||||||
|
// Tell worker to update time point
|
||||||
|
m_traceBufferWritep[0] = VerilatedTraceCommand::TIME_CHANGE;
|
||||||
|
*reinterpret_cast<vluint64_t*>(m_traceBufferWritep + 1) = timeui;
|
||||||
|
m_traceBufferWritep += 3;
|
||||||
|
} else {
|
||||||
|
// Update time point
|
||||||
|
flush();
|
||||||
|
emitTimeChange(timeui);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
// Update time point
|
||||||
|
emitTimeChange(timeui);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Run the callbacks
|
||||||
|
if (VL_UNLIKELY(m_fullDump)) {
|
||||||
|
m_fullDump = false; // No more need for next dump to be full
|
||||||
|
for (vluint32_t i = 0; i < m_fullCbs.size(); ++i) {
|
||||||
|
const CallbackRecord& cbr = m_fullCbs[i];
|
||||||
|
cbr.m_dumpCb(cbr.m_userp, self());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (vluint32_t i = 0; i < m_chgCbs.size(); ++i) {
|
||||||
|
const CallbackRecord& cbr = m_chgCbs[i];
|
||||||
|
cbr.m_dumpCb(cbr.m_userp, self());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (vluint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
|
||||||
|
const CallbackRecord& cbr = m_cleanupCbs[i];
|
||||||
|
cbr.m_dumpCb(cbr.m_userp, self());
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef VL_TRACE_THREADED
|
||||||
|
if (VL_LIKELY(bufferp)) {
|
||||||
|
// Mark end of the trace buffer we just filled
|
||||||
|
*m_traceBufferWritep++ = VerilatedTraceCommand::END;
|
||||||
|
|
||||||
|
// Assert no buffer overflow
|
||||||
|
assert(m_traceBufferWritep - bufferp <= m_traceBufferSize);
|
||||||
|
|
||||||
|
// Pass it to the worker thread
|
||||||
|
m_buffersToWorker.put(bufferp);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// Non-hot path internal interface to Verilator generated code
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void VerilatedTrace<VL_DERIVED_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
|
||||||
|
CallbackRecord& cbRec) {
|
||||||
|
m_assertOne.check();
|
||||||
|
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
|
||||||
|
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
|
||||||
|
+ " called with already open file");
|
||||||
|
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||||
|
} // LCOV_EXCL_STOP
|
||||||
|
cbVec.push_back(cbRec);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::addInitCb(initCb_t cb, void* userp) {
|
||||||
|
CallbackRecord cbr(cb, userp);
|
||||||
|
addCallbackRecord(m_initCbs, cbr);
|
||||||
|
}
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::addFullCb(dumpCb_t cb, void* userp) {
|
||||||
|
CallbackRecord cbr(cb, userp);
|
||||||
|
addCallbackRecord(m_fullCbs, cbr);
|
||||||
|
}
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::addChgCb(dumpCb_t cb, void* userp) {
|
||||||
|
CallbackRecord cbr(cb, userp);
|
||||||
|
addCallbackRecord(m_chgCbs, cbr);
|
||||||
|
}
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::addCleanupCb(dumpCb_t cb, void* userp) {
|
||||||
|
CallbackRecord cbr(cb, userp);
|
||||||
|
addCallbackRecord(m_cleanupCbs, cbr);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Hot path internal interface to Verilator generated code
|
||||||
|
|
||||||
|
// These functions must write the new value back into the old value store,
|
||||||
|
// and subsequently call the format specific emit* implementations. Note
|
||||||
|
// that this file must be included in the format specific implementation, so
|
||||||
|
// the emit* functions can be inlined for performance.
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::fullBit(vluint32_t* oldp, CData newval) {
|
||||||
|
*oldp = newval;
|
||||||
|
self()->emitBit(oldp - m_sigs_oldvalp, newval);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void VerilatedTrace<VL_DERIVED_T>::fullCData(vluint32_t* oldp, CData newval, int bits) {
|
||||||
|
*oldp = newval;
|
||||||
|
self()->emitCData(oldp - m_sigs_oldvalp, newval, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void VerilatedTrace<VL_DERIVED_T>::fullSData(vluint32_t* oldp, SData newval, int bits) {
|
||||||
|
*oldp = newval;
|
||||||
|
self()->emitSData(oldp - m_sigs_oldvalp, newval, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void VerilatedTrace<VL_DERIVED_T>::fullIData(vluint32_t* oldp, IData newval, int bits) {
|
||||||
|
*oldp = newval;
|
||||||
|
self()->emitIData(oldp - m_sigs_oldvalp, newval, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void VerilatedTrace<VL_DERIVED_T>::fullQData(vluint32_t* oldp, QData newval, int bits) {
|
||||||
|
*reinterpret_cast<QData*>(oldp) = newval;
|
||||||
|
self()->emitQData(oldp - m_sigs_oldvalp, newval, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void VerilatedTrace<VL_DERIVED_T>::fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||||
|
for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newvalp[i];
|
||||||
|
self()->emitWData(oldp - m_sigs_oldvalp, newvalp, bits);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, double newval) {
|
||||||
|
// cppcheck-suppress invalidPointerCast
|
||||||
|
*reinterpret_cast<double*>(oldp) = newval;
|
||||||
|
self()->emitDouble(oldp - m_sigs_oldvalp, newval);
|
||||||
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Primitives converting binary values to strings...
|
||||||
|
|
||||||
|
// All of these take a destination pointer where the string will be emitted,
|
||||||
|
// and a value to convert. There are a couple of variants for efficiency.
|
||||||
|
|
||||||
|
inline static void cvtCDataToStr(char* dstp, CData value) {
|
||||||
|
#ifdef VL_HAVE_SSE2
|
||||||
|
// Similar to cvtSDataToStr but only the bottom 8 byte lanes are used
|
||||||
|
const __m128i a = _mm_cvtsi32_si128(value);
|
||||||
|
const __m128i b = _mm_unpacklo_epi8(a, a);
|
||||||
|
const __m128i c = _mm_shufflelo_epi16(b, 0);
|
||||||
|
const __m128i m = _mm_set1_epi64x(0x0102040810204080);
|
||||||
|
const __m128i d = _mm_cmpeq_epi8(_mm_and_si128(c, m), m);
|
||||||
|
const __m128i result = _mm_sub_epi8(_mm_set1_epi8('0'), d);
|
||||||
|
_mm_storel_epi64(reinterpret_cast<__m128i*>(dstp), result);
|
||||||
|
#else
|
||||||
|
dstp[0] = '0' | static_cast<char>((value >> 7) & 1);
|
||||||
|
dstp[1] = '0' | static_cast<char>((value >> 6) & 1);
|
||||||
|
dstp[2] = '0' | static_cast<char>((value >> 5) & 1);
|
||||||
|
dstp[3] = '0' | static_cast<char>((value >> 4) & 1);
|
||||||
|
dstp[4] = '0' | static_cast<char>((value >> 3) & 1);
|
||||||
|
dstp[5] = '0' | static_cast<char>((value >> 2) & 1);
|
||||||
|
dstp[6] = '0' | static_cast<char>((value >> 1) & 1);
|
||||||
|
dstp[7] = '0' | static_cast<char>(value & 1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void cvtSDataToStr(char* dstp, SData value) {
|
||||||
|
#ifdef VL_HAVE_SSE2
|
||||||
|
// We want each bit in the 16-bit input value to end up in a byte lane
|
||||||
|
// within the 128-bit XMM register. Note that x86 is little-endian and we
|
||||||
|
// want the MSB of the input at the low address, so we will bit-reverse
|
||||||
|
// at the same time.
|
||||||
|
|
||||||
|
// Put value in bottom of 128-bit register a[15:0] = value
|
||||||
|
const __m128i a = _mm_cvtsi32_si128(value);
|
||||||
|
// Interleave bytes with themselves
|
||||||
|
// b[15: 0] = {2{a[ 7:0]}} == {2{value[ 7:0]}}
|
||||||
|
// b[31:16] = {2{a[15:8]}} == {2{value[15:8]}}
|
||||||
|
const __m128i b = _mm_unpacklo_epi8(a, a);
|
||||||
|
// Shuffle bottom 64 bits, note swapping high bytes with low bytes
|
||||||
|
// c[31: 0] = {2{b[31:16]}} == {4{value[15:8}}
|
||||||
|
// c[63:32] = {2{b[15: 0]}} == {4{value[ 7:0}}
|
||||||
|
const __m128i c = _mm_shufflelo_epi16(b, 0x05);
|
||||||
|
// Shuffle whole register
|
||||||
|
// d[ 63: 0] = {2{c[31: 0]}} == {8{value[15:8}}
|
||||||
|
// d[126:54] = {2{c[63:32]}} == {8{value[ 7:0}}
|
||||||
|
const __m128i d = _mm_shuffle_epi32(c, 0x50);
|
||||||
|
// Test each bit within the bytes, this sets each byte lane to 0
|
||||||
|
// if the bit for that lane is 0 and to 0xff if the bit is 1.
|
||||||
|
const __m128i m = _mm_set1_epi64x(0x0102040810204080);
|
||||||
|
const __m128i e = _mm_cmpeq_epi8(_mm_and_si128(d, m), m);
|
||||||
|
// Convert to ASCII by subtracting the masks from ASCII '0':
|
||||||
|
// '0' - 0 is '0', '0' - -1 is '1'
|
||||||
|
const __m128i result = _mm_sub_epi8(_mm_set1_epi8('0'), e);
|
||||||
|
// Store the 16 characters to the un-aligned buffer
|
||||||
|
_mm_storeu_si128(reinterpret_cast<__m128i*>(dstp), result);
|
||||||
|
#else
|
||||||
|
cvtCDataToStr(dstp, value >> 8);
|
||||||
|
cvtCDataToStr(dstp + 8, value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void cvtIDataToStr(char* dstp, IData value) {
|
||||||
|
#ifdef VL_HAVE_AVX2
|
||||||
|
// Similar to cvtSDataToStr but the bottom 16-bits are processed in the
|
||||||
|
// top half of the YMM registerss
|
||||||
|
const __m256i a = _mm256_insert_epi32(_mm256_undefined_si256(), value, 0);
|
||||||
|
const __m256i b = _mm256_permute4x64_epi64(a, 0);
|
||||||
|
const __m256i s = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||||
|
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3);
|
||||||
|
const __m256i c = _mm256_shuffle_epi8(b, s);
|
||||||
|
const __m256i m = _mm256_set1_epi64x(0x0102040810204080);
|
||||||
|
const __m256i d = _mm256_cmpeq_epi8(_mm256_and_si256(c, m), m);
|
||||||
|
const __m256i result = _mm256_sub_epi8(_mm256_set1_epi8('0'), d);
|
||||||
|
_mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp), result);
|
||||||
|
#else
|
||||||
|
cvtSDataToStr(dstp, value >> 16);
|
||||||
|
cvtSDataToStr(dstp + 16, value);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static void cvtQDataToStr(char* dstp, QData value) {
|
||||||
|
cvtIDataToStr(dstp, value >> 32);
|
||||||
|
cvtIDataToStr(dstp + 32, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define cvtEDataToStr cvtIDataToStr
|
||||||
@@ -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"
|
||||||
|
|
||||||
@@ -41,78 +41,70 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
// Abstract 'vl_hash' and 'vl_equal_to' templates.
|
// Abstract 'vl_hash' and 'vl_equal_to' templates.
|
||||||
template <typename T> struct vl_hash {
|
template <typename T> struct vl_hash { size_t operator()(const T& k) const; };
|
||||||
size_t operator()(const T& k) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T> struct vl_equal_to {
|
template <typename T> struct vl_equal_to { bool operator()(const T& a, const T& b) const; };
|
||||||
bool operator()(const T& a, const T& b) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Specializations of 'vl_hash' and 'vl_equal_to'.
|
// Specializations of 'vl_hash' and 'vl_equal_to'.
|
||||||
inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
|
inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
|
||||||
const vluint8_t* bufp = static_cast<const vluint8_t*>(vbufp);
|
const vluint8_t* bufp = static_cast<const vluint8_t*>(vbufp);
|
||||||
size_t hash = 0;
|
size_t hash = 0;
|
||||||
for (size_t i = 0; i < nbytes; i++) {
|
for (size_t i = 0; i < nbytes; i++) {
|
||||||
hash = bufp[i] + 31u * hash; // the K&R classic!
|
hash = bufp[i] + 31U * hash; // the K&R classic!
|
||||||
}
|
}
|
||||||
return hash;
|
return hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline size_t
|
template <> inline size_t vl_hash<int>::operator()(const int& k) const { return k; }
|
||||||
vl_hash<unsigned int>::operator()(const unsigned int& k) const {
|
|
||||||
return k;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <> inline bool
|
template <> inline bool vl_equal_to<int>::operator()(const int& a, const int& b) const {
|
||||||
vl_equal_to<unsigned int>::operator()(const unsigned int& a,
|
|
||||||
const unsigned int& b) const {
|
|
||||||
return a == b;
|
return a == b;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline size_t
|
template <> inline size_t vl_hash<unsigned int>::operator()(const unsigned int& k) const {
|
||||||
vl_hash<std::string>::operator()(const std::string& k) const {
|
return k;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <>
|
||||||
|
inline bool vl_equal_to<unsigned int>::operator()(const unsigned int& a,
|
||||||
|
const unsigned int& b) const {
|
||||||
|
return a == b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> inline size_t vl_hash<std::string>::operator()(const std::string& k) const {
|
||||||
return vl_hash_bytes(k.data(), k.size());
|
return vl_hash_bytes(k.data(), k.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <> inline bool
|
template <>
|
||||||
vl_equal_to<std::string>::operator()(const std::string& a,
|
inline bool vl_equal_to<std::string>::operator()(const std::string& a,
|
||||||
const std::string& b) const {
|
const std::string& b) const {
|
||||||
// Don't scan the strings if the sizes are different.
|
// Don't scan the strings if the sizes are different.
|
||||||
if (a.size() != b.size()) {
|
if (a.size() != b.size()) return false;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return (0 == a.compare(b)); // Must scan.
|
return (0 == a.compare(b)); // Must scan.
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T> struct vl_hash<T*> {
|
template <typename T> struct vl_hash<T*> {
|
||||||
size_t operator()(T* kp) const {
|
size_t operator()(T* kp) const {
|
||||||
return ((sizeof(size_t) == sizeof(kp))
|
return ((sizeof(size_t) == sizeof(kp)) ? reinterpret_cast<size_t>(kp)
|
||||||
? reinterpret_cast<size_t>(kp)
|
: vl_hash_bytes(&kp, sizeof(kp)));
|
||||||
: vl_hash_bytes(&kp, sizeof(kp)));
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> struct vl_equal_to<T*> {
|
template <typename T> struct vl_equal_to<T*> {
|
||||||
bool operator()(T* ap, T* bp) const {
|
bool operator()(T* ap, T* bp) const { return ap == bp; }
|
||||||
return ap == bp;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
//
|
//
|
||||||
/// Functional clone of the std::unordered_set hash table.
|
/// Functional clone of the std::unordered_set hash table.
|
||||||
template <class T_Key,
|
template <class T_Key, class T_Hash = vl_hash<T_Key>, class T_Equal = vl_equal_to<T_Key> >
|
||||||
class T_Hash = vl_hash<T_Key>,
|
|
||||||
class T_Equal = vl_equal_to<T_Key> >
|
|
||||||
class vl_unordered_set {
|
class vl_unordered_set {
|
||||||
public:
|
public:
|
||||||
// TYPES
|
// TYPES
|
||||||
typedef std::list<T_Key> Bucket;
|
typedef std::list<T_Key> Bucket;
|
||||||
enum RehashType { GROW, SHRINK };
|
enum RehashType { GROW, SHRINK };
|
||||||
|
|
||||||
template <class KK, class VV,
|
template <class KK, class VV, class HH, class EQ> friend class vl_unordered_map;
|
||||||
class HH, class EQ> friend class vl_unordered_map;
|
|
||||||
|
|
||||||
class iterator {
|
class iterator {
|
||||||
protected:
|
protected:
|
||||||
@@ -123,29 +115,23 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
iterator(size_t bucketIdx, typename Bucket::iterator bit,
|
iterator(size_t bucketIdx, typename Bucket::iterator bit, const vl_unordered_set* setp)
|
||||||
const vl_unordered_set* setp)
|
: m_bucketIdx(bucketIdx)
|
||||||
: m_bucketIdx(bucketIdx), m_bit(bit), m_setp(setp) {}
|
, m_bit(bit)
|
||||||
|
, m_setp(setp) {}
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
const T_Key& operator*() const {
|
const T_Key& operator*() const { return *m_bit; }
|
||||||
return *m_bit;
|
|
||||||
}
|
|
||||||
// This should really be 'const T_Key*' type for unordered_set,
|
// This should really be 'const T_Key*' type for unordered_set,
|
||||||
// however this iterator is shared with unordered_map whose
|
// however this iterator is shared with unordered_map whose
|
||||||
// operator-> returns a non-const ValueType*, so keep this
|
// operator-> returns a non-const ValueType*, so keep this
|
||||||
// non-const to avoid having to define a whole separate iterator
|
// non-const to avoid having to define a whole separate iterator
|
||||||
// for unordered_map.
|
// for unordered_map.
|
||||||
T_Key* operator->() const {
|
T_Key* operator->() const { return &(*m_bit); }
|
||||||
return &(*m_bit);
|
|
||||||
}
|
|
||||||
bool operator==(const iterator& other) const {
|
bool operator==(const iterator& other) const {
|
||||||
return ((m_bucketIdx == other.m_bucketIdx)
|
return ((m_bucketIdx == other.m_bucketIdx) && (m_bit == other.m_bit));
|
||||||
&& (m_bit == other.m_bit));
|
|
||||||
}
|
|
||||||
bool operator!=(const iterator& other) const {
|
|
||||||
return (!this->operator==(other));
|
|
||||||
}
|
}
|
||||||
|
bool operator!=(const iterator& other) const { return (!this->operator==(other)); }
|
||||||
void advanceUntilValid() {
|
void advanceUntilValid() {
|
||||||
while (true) {
|
while (true) {
|
||||||
if (m_bit != m_setp->m_bucketsp[m_bucketIdx].end()) {
|
if (m_bit != m_setp->m_bucketsp[m_bucketIdx].end()) {
|
||||||
@@ -176,14 +162,14 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
size_t m_numElements; // Number of entries present.
|
size_t m_numElements; // Number of entries present.
|
||||||
size_t m_log2Buckets; // Log-base-2 of the number of buckets.
|
size_t m_log2Buckets; // Log-base-2 of the number of buckets.
|
||||||
mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL;
|
mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL;
|
||||||
// // we'll allocate it on the fly when
|
// // we'll allocate it on the fly when
|
||||||
// // the first entries are created.
|
// // the first entries are created.
|
||||||
Bucket m_emptyBucket; // A fake bucket, used to construct end().
|
Bucket m_emptyBucket; // A fake bucket, used to construct end().
|
||||||
T_Hash m_hash; // Hash function provider.
|
T_Hash m_hash; // Hash function provider.
|
||||||
T_Equal m_equal; // Equal-to function provider.
|
T_Equal m_equal; // Equal-to function provider.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
@@ -202,26 +188,20 @@ public:
|
|||||||
, m_equal() {
|
, m_equal() {
|
||||||
if (other.m_bucketsp) {
|
if (other.m_bucketsp) {
|
||||||
m_bucketsp = new Bucket[numBuckets()];
|
m_bucketsp = new Bucket[numBuckets()];
|
||||||
for (size_t i = 0; i < numBuckets(); i++) {
|
for (size_t i = 0; i < numBuckets(); i++) m_bucketsp[i] = other.m_bucketsp[i];
|
||||||
m_bucketsp[i] = other.m_bucketsp[i];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
~vl_unordered_set() {
|
~vl_unordered_set() { VL_DO_DANGLING(delete[] m_bucketsp, m_bucketsp); }
|
||||||
VL_DO_DANGLING(delete [] m_bucketsp, m_bucketsp);
|
|
||||||
}
|
|
||||||
|
|
||||||
vl_unordered_set& operator=(const vl_unordered_set& other) {
|
vl_unordered_set& operator=(const vl_unordered_set& other) {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
clear();
|
clear();
|
||||||
delete [] m_bucketsp;
|
delete[] m_bucketsp;
|
||||||
m_numElements = other.m_numElements;
|
m_numElements = other.m_numElements;
|
||||||
m_log2Buckets = other.m_log2Buckets;
|
m_log2Buckets = other.m_log2Buckets;
|
||||||
if (other.m_bucketsp) {
|
if (other.m_bucketsp) {
|
||||||
m_bucketsp = new Bucket[numBuckets()];
|
m_bucketsp = new Bucket[numBuckets()];
|
||||||
for (size_t i = 0; i < numBuckets(); i++) {
|
for (size_t i = 0; i < numBuckets(); i++) m_bucketsp[i] = other.m_bucketsp[i];
|
||||||
m_bucketsp[i] = other.m_bucketsp[i];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
m_bucketsp = NULL;
|
m_bucketsp = NULL;
|
||||||
}
|
}
|
||||||
@@ -251,24 +231,20 @@ public:
|
|||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
const_iterator end() const {
|
const_iterator end() const {
|
||||||
return iterator(VL_ULL(0xFFFFFFFFFFFFFFFF),
|
return iterator(0xFFFFFFFFFFFFFFFFULL, const_cast<Bucket&>(m_emptyBucket).begin(), this);
|
||||||
const_cast<Bucket&>(m_emptyBucket).begin(), this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool empty() const { return m_numElements == 0; }
|
bool empty() const { return m_numElements == 0; }
|
||||||
|
|
||||||
size_t size() const { return m_numElements; }
|
size_t size() const { return m_numElements; }
|
||||||
|
|
||||||
size_t count(const T_Key& key) const {
|
size_t count(const T_Key& key) const { return (find(key) == end()) ? 0 : 1; }
|
||||||
return (find(key) == end()) ? 0 : 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t hashToBucket(size_t hashVal) const {
|
size_t hashToBucket(size_t hashVal) const { return hashToBucket(hashVal, m_log2Buckets); }
|
||||||
return hashToBucket(hashVal, m_log2Buckets);
|
|
||||||
}
|
|
||||||
static size_t hashToBucket(size_t hashVal, unsigned log2Buckets) {
|
static size_t hashToBucket(size_t hashVal, unsigned log2Buckets) {
|
||||||
// Fibonacci hashing
|
// Fibonacci hashing, see
|
||||||
// See https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/
|
// https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization
|
||||||
|
// -that-the-world-forgot-or-a-better-alternative-to-integer-modulo/
|
||||||
//
|
//
|
||||||
// * The magic numbers below are UINT_MAX/phi where phi is the
|
// * The magic numbers below are UINT_MAX/phi where phi is the
|
||||||
// golden ratio number (1.618...) for either 64- or 32-bit
|
// golden ratio number (1.618...) for either 64- or 32-bit
|
||||||
@@ -278,11 +254,8 @@ 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 = hashVal * ((sizeof(size_t) == 8)
|
size_t mult = hashVal * ((sizeof(size_t) == 8) ? 11400714819323198485ULL : 2654435769lu);
|
||||||
? VL_ULL(11400714819323198485)
|
size_t result = (mult >> (((sizeof(size_t) == 8) ? 64 : 32) - log2Buckets));
|
||||||
: 2654435769lu);
|
|
||||||
size_t result = (mult >> (((sizeof(size_t) == 8)
|
|
||||||
? 64 : 32) - log2Buckets));
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -292,19 +265,15 @@ public:
|
|||||||
initBuckets();
|
initBuckets();
|
||||||
Bucket* bucketp = &m_bucketsp[bucketIdxOut];
|
Bucket* bucketp = &m_bucketsp[bucketIdxOut];
|
||||||
|
|
||||||
for (typename Bucket::iterator it = bucketp->begin();
|
for (typename Bucket::iterator it = bucketp->begin(); it != bucketp->end(); ++it) {
|
||||||
it != bucketp->end(); ++it) {
|
if (m_equal.operator()(*it, key)) return iterator(bucketIdxOut, it, this);
|
||||||
if (m_equal.operator()(*it, key)) {
|
|
||||||
return iterator(bucketIdxOut, it, this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
const_iterator find(const T_Key& key) const {
|
const_iterator find(const T_Key& key) const {
|
||||||
size_t bucketIdx;
|
size_t bucketIdx;
|
||||||
return const_cast<vl_unordered_set*>(this)->find_internal(key,
|
return const_cast<vl_unordered_set*>(this)->find_internal(key, bucketIdx);
|
||||||
bucketIdx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator find(const T_Key& key) {
|
iterator find(const T_Key& key) {
|
||||||
@@ -358,9 +327,7 @@ public:
|
|||||||
// for the Scoreboard in V3Partition, which begins tracking
|
// for the Scoreboard in V3Partition, which begins tracking
|
||||||
// a huge number of vertices and then tracks a successively
|
// a huge number of vertices and then tracks a successively
|
||||||
// smaller number over time.
|
// smaller number over time.
|
||||||
if (needToRehash(SHRINK)) {
|
if (needToRehash(SHRINK)) rehash(SHRINK);
|
||||||
rehash(SHRINK);
|
|
||||||
}
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
@@ -376,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();
|
||||||
@@ -409,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++) {
|
||||||
@@ -419,8 +386,7 @@ private:
|
|||||||
size_t new_idx = hashToBucket(hash, new_log2Buckets);
|
size_t new_idx = hashToBucket(hash, new_log2Buckets);
|
||||||
// Avoid mallocing one list elem and freeing another;
|
// Avoid mallocing one list elem and freeing another;
|
||||||
// splice just moves it over.
|
// splice just moves it over.
|
||||||
new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(),
|
new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(), m_bucketsp[i], bit);
|
||||||
m_bucketsp[i], bit);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,9 +399,7 @@ private:
|
|||||||
//===================================================================
|
//===================================================================
|
||||||
//
|
//
|
||||||
/// Functional clone of the std::unordered_map hash table.
|
/// Functional clone of the std::unordered_map hash table.
|
||||||
template <class T_Key,
|
template <class T_Key, class T_Value, class T_Hash = vl_hash<T_Key>,
|
||||||
class T_Value,
|
|
||||||
class T_Hash = vl_hash<T_Key>,
|
|
||||||
class T_Equal = vl_equal_to<T_Key> >
|
class T_Equal = vl_equal_to<T_Key> >
|
||||||
class vl_unordered_map {
|
class vl_unordered_map {
|
||||||
private:
|
private:
|
||||||
@@ -445,6 +409,7 @@ private:
|
|||||||
class KeyHash {
|
class KeyHash {
|
||||||
private:
|
private:
|
||||||
T_Hash key_hash;
|
T_Hash key_hash;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KeyHash() {}
|
KeyHash() {}
|
||||||
size_t operator()(const KeyValPair& kv_pair) const {
|
size_t operator()(const KeyValPair& kv_pair) const {
|
||||||
@@ -455,6 +420,7 @@ private:
|
|||||||
class KeyEqual {
|
class KeyEqual {
|
||||||
private:
|
private:
|
||||||
T_Equal key_eq;
|
T_Equal key_eq;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
KeyEqual() {}
|
KeyEqual() {}
|
||||||
bool operator()(const KeyValPair& kv_a, const KeyValPair& kv_b) const {
|
bool operator()(const KeyValPair& kv_a, const KeyValPair& kv_b) const {
|
||||||
@@ -491,24 +457,19 @@ public:
|
|||||||
size_t bucketIdxOut = m_set.hashToBucket(hash);
|
size_t bucketIdxOut = m_set.hashToBucket(hash);
|
||||||
typename MapSet::Bucket* bucketp = m_set.getBucket(bucketIdxOut);
|
typename MapSet::Bucket* bucketp = m_set.getBucket(bucketIdxOut);
|
||||||
|
|
||||||
for (typename MapSet::Bucket::iterator it = bucketp->begin();
|
for (typename MapSet::Bucket::iterator it = bucketp->begin(); it != bucketp->end(); ++it) {
|
||||||
it != bucketp->end(); ++it) {
|
if (mapEq.operator()(it->first, k)) return iterator(bucketIdxOut, it, &m_set);
|
||||||
if (mapEq.operator()(it->first, k)) {
|
|
||||||
return iterator(bucketIdxOut, it, &m_set);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
const_iterator find(const T_Key& k) const {
|
const_iterator find(const T_Key& k) const {
|
||||||
return const_cast<vl_unordered_map*>(this)->find(k);
|
return const_cast<vl_unordered_map*>(this)->find(k);
|
||||||
}
|
}
|
||||||
std::pair<iterator, bool> insert(const KeyValPair& val) {
|
std::pair<iterator, bool> insert(const KeyValPair& val) { return m_set.insert(val); }
|
||||||
return m_set.insert(val);
|
|
||||||
}
|
|
||||||
iterator erase(iterator it) { return m_set.erase(it); }
|
iterator erase(iterator it) { return m_set.erase(it); }
|
||||||
size_t erase(const T_Key& k) {
|
size_t erase(const T_Key& k) {
|
||||||
iterator it = find(k);
|
iterator it = find(k);
|
||||||
if (it == end()) { return 0; }
|
if (it == end()) return 0;
|
||||||
m_set.erase(it);
|
m_set.erase(it);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -517,9 +478,7 @@ public:
|
|||||||
// std::unordered_map::operator[] relies on it too.
|
// std::unordered_map::operator[] relies on it too.
|
||||||
KeyValPair dummy = std::make_pair(k, T_Value());
|
KeyValPair dummy = std::make_pair(k, T_Value());
|
||||||
iterator it = m_set.find(dummy);
|
iterator it = m_set.find(dummy);
|
||||||
if (it == m_set.end()) {
|
if (it == m_set.end()) it = m_set.insert(dummy).first;
|
||||||
it = m_set.insert(dummy).first;
|
|
||||||
}
|
|
||||||
// For the 'set', it's generally not safe to modify
|
// For the 'set', it's generally not safe to modify
|
||||||
// the value after deref. For the 'map' though, we know
|
// the value after deref. For the 'map' though, we know
|
||||||
// it's safe to modify the value field and we can allow it:
|
// it's safe to modify the value field and we can allow it:
|
||||||
|
|||||||
+458
-335
File diff suppressed because it is too large
Load Diff
+187
-279
@@ -20,15 +20,14 @@
|
|||||||
#ifndef _VERILATED_VCD_C_H_
|
#ifndef _VERILATED_VCD_C_H_
|
||||||
#define _VERILATED_VCD_C_H_ 1
|
#define _VERILATED_VCD_C_H_ 1
|
||||||
|
|
||||||
#include "verilatedos.h"
|
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
|
#include "verilated_trace.h"
|
||||||
|
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
class VerilatedVcd;
|
class VerilatedVcd;
|
||||||
class VerilatedVcdCallInfo;
|
|
||||||
|
|
||||||
// SPDIFF_ON
|
// SPDIFF_ON
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -48,64 +47,39 @@ public:
|
|||||||
virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE;
|
virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE;
|
||||||
};
|
};
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
// VerilatedVcdSig
|
|
||||||
/// Internal data on one signal being traced.
|
|
||||||
|
|
||||||
class VerilatedVcdSig {
|
|
||||||
protected:
|
|
||||||
friend class VerilatedVcd;
|
|
||||||
vluint32_t m_code; ///< VCD file code number
|
|
||||||
int m_bits; ///< Size of value in bits
|
|
||||||
VerilatedVcdSig(vluint32_t code, int bits)
|
|
||||||
: m_code(code)
|
|
||||||
, m_bits(bits) {}
|
|
||||||
public:
|
|
||||||
~VerilatedVcdSig() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
//=============================================================================
|
|
||||||
|
|
||||||
typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluint32_t code);
|
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedVcd
|
// VerilatedVcd
|
||||||
/// Base class to create a Verilator VCD dump
|
/// Base class to create a Verilator VCD dump
|
||||||
/// This is an internally used class - see VerilatedVcdC for what to call from applications
|
/// This is an internally used class - see VerilatedVcdC for what to call from applications
|
||||||
|
|
||||||
class VerilatedVcd {
|
class VerilatedVcd : public VerilatedTrace<VerilatedVcd> {
|
||||||
private:
|
private:
|
||||||
VerilatedVcdFile* m_filep; ///< File we're writing to
|
// Give the superclass access to private bits (to avoid virtual functions)
|
||||||
bool m_fileNewed; ///< m_filep needs destruction
|
friend class VerilatedTrace<VerilatedVcd>;
|
||||||
bool m_isOpen; ///< True indicates open file
|
|
||||||
bool m_evcd; ///< True for evcd format
|
|
||||||
std::string m_filename; ///< Filename we're writing to (if open)
|
|
||||||
vluint64_t m_rolloverMB; ///< MB of file size to rollover at
|
|
||||||
char m_scopeEscape; ///< Character to separate scope components
|
|
||||||
int m_modDepth; ///< Depth of module hierarchy
|
|
||||||
bool m_fullDump; ///< True indicates dump ignoring if changed
|
|
||||||
vluint32_t m_nextCode; ///< Next code number to assign
|
|
||||||
std::string m_modName; ///< Module name being traced now
|
|
||||||
double m_timeRes; ///< Time resolution (ns/ms etc)
|
|
||||||
double m_timeUnit; ///< Time units (ns/ms etc)
|
|
||||||
vluint64_t m_timeLastDump; ///< Last time we did a dump
|
|
||||||
|
|
||||||
char* m_wrBufp; ///< Output buffer
|
//=========================================================================
|
||||||
char* m_wrFlushp; ///< Output buffer flush trigger location
|
// VCD specific internals
|
||||||
char* m_writep; ///< Write pointer into output buffer
|
|
||||||
vluint64_t m_wrChunkSize; ///< Output buffer size
|
|
||||||
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
|
|
||||||
|
|
||||||
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
|
VerilatedVcdFile* m_filep; ///< File we're writing to
|
||||||
typedef std::vector<VerilatedVcdSig> SigVec;
|
bool m_fileNewed; ///< m_filep needs destruction
|
||||||
SigVec m_sigs; ///< Pointer to signal information
|
bool m_isOpen; ///< True indicates open file
|
||||||
typedef std::vector<VerilatedVcdCallInfo*> CallbackVec;
|
bool m_evcd; ///< True for evcd format
|
||||||
CallbackVec m_callbacks; ///< Routines to perform dumping
|
std::string m_filename; ///< Filename we're writing to (if open)
|
||||||
typedef std::map<std::string,std::string> NameMap;
|
vluint64_t m_rolloverMB; ///< MB of file size to rollover at
|
||||||
|
int m_modDepth; ///< Depth of module hierarchy
|
||||||
|
|
||||||
|
char* m_wrBufp; ///< Output buffer
|
||||||
|
char* m_wrFlushp; ///< Output buffer flush trigger location
|
||||||
|
char* m_writep; ///< Write pointer into output buffer
|
||||||
|
vluint64_t m_wrChunkSize; ///< Output buffer size
|
||||||
|
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
|
||||||
|
|
||||||
|
std::vector<char> m_suffixes; ///< VCD line end string codes + metadata
|
||||||
|
const char* m_suffixesp; ///< Pointer to first element of above
|
||||||
|
|
||||||
|
typedef std::map<std::string, std::string> NameMap;
|
||||||
NameMap* m_namemapp; ///< List of names for the header
|
NameMap* m_namemapp; ///< List of names for the header
|
||||||
|
|
||||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
|
||||||
|
|
||||||
void bufferResize(vluint64_t minsize);
|
void bufferResize(vluint64_t minsize);
|
||||||
void bufferFlush() VL_MT_UNSAFE_ONE;
|
void bufferFlush() VL_MT_UNSAFE_ONE;
|
||||||
inline void bufferCheck() {
|
inline void bufferCheck() {
|
||||||
@@ -126,220 +100,143 @@ private:
|
|||||||
bool tri, bool bussed, int msb, int lsb);
|
bool tri, bool bussed, int msb, int lsb);
|
||||||
|
|
||||||
void dumpHeader();
|
void dumpHeader();
|
||||||
void dumpPrep(vluint64_t timeui);
|
|
||||||
void dumpFull(vluint64_t timeui);
|
char* writeCode(char* writep, vluint32_t code);
|
||||||
// cppcheck-suppress functionConst
|
|
||||||
void dumpDone();
|
void finishLine(vluint32_t code, char* writep);
|
||||||
inline void printCode(vluint32_t code) {
|
|
||||||
*m_writep++ = static_cast<char>('!' + code % 94);
|
/// Flush any remaining data from all files
|
||||||
code /= 94;
|
static void flush_all() VL_MT_UNSAFE_ONE;
|
||||||
while (code) {
|
|
||||||
code--;
|
|
||||||
*m_writep++ = static_cast<char>('!' + code % 94);
|
|
||||||
code /= 94;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
static std::string stringCode(vluint32_t code) VL_PURE {
|
|
||||||
std::string out;
|
|
||||||
out += static_cast<char>('!' + code % 94);
|
|
||||||
code /= 94;
|
|
||||||
while (code) {
|
|
||||||
code--;
|
|
||||||
out += static_cast<char>('!' + code % 94);
|
|
||||||
code /= 94;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedVcd);
|
VL_UNCOPYABLE(VerilatedVcd);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
//=========================================================================
|
||||||
|
// Implementation of VerilatedTrace interface
|
||||||
|
|
||||||
|
// Implementations of protected virtual methods for VerilatedTrace
|
||||||
|
void emitTimeChange(vluint64_t timeui) VL_OVERRIDE;
|
||||||
|
|
||||||
|
// Hooks called from VerilatedTrace
|
||||||
|
bool preFullDump() VL_OVERRIDE { return isOpen(); }
|
||||||
|
bool preChangeDump() VL_OVERRIDE;
|
||||||
|
|
||||||
|
// Implementations of duck-typed methods for VerilatedTrace. These are
|
||||||
|
// called from only one place (namely full*) so always inline them.
|
||||||
|
inline void emitBit(vluint32_t code, CData newval);
|
||||||
|
inline void emitCData(vluint32_t code, CData newval, int bits);
|
||||||
|
inline void emitSData(vluint32_t code, SData 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 emitWData(vluint32_t code, const WData* newvalp, int bits);
|
||||||
|
inline void emitDouble(vluint32_t code, double newval);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
//=========================================================================
|
||||||
|
// External interface to client code
|
||||||
|
|
||||||
explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
|
explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
|
||||||
~VerilatedVcd();
|
~VerilatedVcd();
|
||||||
/// Routines can only be called from one thread; allow next call from different thread
|
|
||||||
void changeThread() { m_assertOne.changeThread(); }
|
|
||||||
|
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
/// Set size in megabytes after which new file should be created
|
/// Set size in megabytes after which new file should be created
|
||||||
void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB = rolloverMB; }
|
void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB = rolloverMB; }
|
||||||
/// Is file open?
|
|
||||||
bool isOpen() const { return m_isOpen; }
|
|
||||||
/// Change character that splits scopes. Note whitespace are ALWAYS escapes.
|
|
||||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
|
||||||
/// Is this an escape?
|
|
||||||
inline bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; }
|
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
void open(const char* filename) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
/// Open the file; call isOpen() to see if errors
|
||||||
void openNext(bool incFilename); ///< Open next data-only file
|
void open(const char* filename) VL_MT_UNSAFE_ONE;
|
||||||
void close() VL_MT_UNSAFE_ONE; ///< Close the file
|
/// Open next data-only file
|
||||||
|
void openNext(bool incFilename) VL_MT_UNSAFE_ONE;
|
||||||
|
/// Close the file
|
||||||
|
void close() VL_MT_UNSAFE_ONE;
|
||||||
/// Flush any remaining data to this file
|
/// Flush any remaining data to this file
|
||||||
void flush() VL_MT_UNSAFE_ONE { bufferFlush(); }
|
void flush() VL_MT_UNSAFE_ONE;
|
||||||
/// Flush any remaining data from all files
|
/// Is file open?
|
||||||
static void flush_all() VL_MT_UNSAFE_ONE;
|
bool isOpen() const { return m_isOpen; }
|
||||||
|
|
||||||
void set_time_unit(const char* unitp); ///< Set time units (s/ms, defaults to ns)
|
//=========================================================================
|
||||||
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
|
// Internal interface to Verilator generated code
|
||||||
|
|
||||||
void set_time_resolution(const char* unitp); ///< Set time resolution (s/ms, defaults to ns)
|
void declBit(vluint32_t code, const char* name, bool array, int arraynum);
|
||||||
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
|
void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||||
|
void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||||
|
void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||||
|
void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
|
||||||
|
|
||||||
double timescaleToDouble(const char* unitp);
|
#ifdef VL_TRACE_VCD_OLD_API
|
||||||
std::string doubleToTimescale(double value);
|
//=========================================================================
|
||||||
|
// 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.
|
||||||
|
|
||||||
/// Inside dumping routines, called each cycle to make the dump
|
void declTriBit(vluint32_t code, const char* name, bool array, int arraynum);
|
||||||
void dump(vluint64_t timeui);
|
void declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||||
/// Call dump with a absolute unscaled time in seconds
|
void declTriQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||||
void dumpSeconds(double secs) { dump(static_cast<vluint64_t>(secs * m_timeRes)); }
|
int lsb);
|
||||||
|
void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||||
|
int lsb);
|
||||||
|
|
||||||
/// Inside dumping routines, declare callbacks for tracings
|
void fullBit(vluint32_t* oldp, CData newval) { fullBit(oldp - this->oldp(0), newval); }
|
||||||
void addCallback(VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb,
|
void fullCData(vluint32_t* oldp, CData newval, int bits) {
|
||||||
VerilatedVcdCallback_t changecb,
|
fullBus(oldp - this->oldp(0), newval, bits);
|
||||||
void* userthis) VL_MT_UNSAFE_ONE;
|
}
|
||||||
|
void fullSData(vluint32_t* oldp, SData newval, int bits) {
|
||||||
|
fullBus(oldp - this->oldp(0), newval, bits);
|
||||||
|
}
|
||||||
|
void fullIData(vluint32_t* oldp, IData newval, int bits) {
|
||||||
|
fullBus(oldp - this->oldp(0), newval, bits);
|
||||||
|
}
|
||||||
|
void fullQData(vluint32_t* oldp, QData newval, int bits) {
|
||||||
|
fullQuad(oldp - this->oldp(0), newval, bits);
|
||||||
|
}
|
||||||
|
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||||
|
fullArray(oldp - this->oldp(0), newvalp, bits);
|
||||||
|
}
|
||||||
|
void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); }
|
||||||
|
|
||||||
/// Inside dumping routines, declare a module
|
inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); }
|
||||||
void module(const std::string& name);
|
inline void chgCData(vluint32_t* oldp, CData newval, int bits) {
|
||||||
/// Inside dumping routines, declare a signal
|
chgBus(oldp - this->oldp(0), newval, bits);
|
||||||
void declBit( vluint32_t code, const char* name, bool array, int arraynum);
|
}
|
||||||
void declBus( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
inline void chgSData(vluint32_t* oldp, SData newval, int bits) {
|
||||||
void declQuad( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
chgBus(oldp - this->oldp(0), newval, bits);
|
||||||
void declArray( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
}
|
||||||
void declTriBit( vluint32_t code, const char* name, bool array, int arraynum);
|
inline void chgIData(vluint32_t* oldp, IData newval, int bits) {
|
||||||
void declTriBus( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
chgBus(oldp - this->oldp(0), newval, bits);
|
||||||
void declTriQuad( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
}
|
||||||
void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
inline void chgQData(vluint32_t* oldp, QData newval, int bits) {
|
||||||
void declDouble( vluint32_t code, const char* name, bool array, int arraynum);
|
chgQuad(oldp - this->oldp(0), newval, bits);
|
||||||
void declFloat( vluint32_t code, const char* name, bool array, int arraynum);
|
}
|
||||||
// ... other module_start for submodules (based on cell name)
|
inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||||
|
chgArray(oldp - this->oldp(0), newvalp, bits);
|
||||||
|
}
|
||||||
|
inline void chgDouble(vluint32_t* oldp, double newval) {
|
||||||
|
chgDouble(oldp - this->oldp(0), newval);
|
||||||
|
}
|
||||||
|
|
||||||
/// Inside dumping routines, dump one signal
|
/// Inside dumping routines, dump one signal, faster when not inlined
|
||||||
void fullBit(vluint32_t code, const vluint32_t newval) {
|
/// due to code size reduction.
|
||||||
// Note the &1, so we don't require clean input -- makes more common no change case faster
|
void fullBit(vluint32_t code, const vluint32_t newval);
|
||||||
m_sigs_oldvalp[code] = newval;
|
void fullBus(vluint32_t code, const vluint32_t newval, int bits);
|
||||||
*m_writep++=('0'+static_cast<char>(newval&1)); printCode(code); *m_writep++='\n';
|
void fullQuad(vluint32_t code, const vluint64_t newval, int bits);
|
||||||
bufferCheck();
|
void fullArray(vluint32_t code, const vluint32_t* newvalp, int bits);
|
||||||
}
|
void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits);
|
||||||
void fullBus(vluint32_t code, const vluint32_t newval, int bits) {
|
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
|
||||||
m_sigs_oldvalp[code] = newval;
|
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
|
||||||
*m_writep++='b';
|
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri, int bits);
|
||||||
for (int bit=bits-1; bit>=0; --bit) {
|
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
|
||||||
*m_writep++=((newval&(1L<<bit))?'1':'0');
|
int bits);
|
||||||
}
|
|
||||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
void fullQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
|
||||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) = newval;
|
|
||||||
*m_writep++='b';
|
|
||||||
for (int bit=bits-1; bit>=0; --bit) {
|
|
||||||
*m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0');
|
|
||||||
}
|
|
||||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
|
||||||
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
|
||||||
m_sigs_oldvalp[code + word] = newval[word];
|
|
||||||
}
|
|
||||||
*m_writep++ = 'b';
|
|
||||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
|
||||||
*m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0');
|
|
||||||
}
|
|
||||||
*m_writep ++= ' '; printCode(code); *m_writep ++= '\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
void fullArray(vluint32_t code, const vluint64_t* newval, int bits) {
|
|
||||||
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) {
|
|
||||||
m_sigs_oldvalp[code + word] = newval[word];
|
|
||||||
}
|
|
||||||
*m_writep ++= 'b';
|
|
||||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
|
||||||
*m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0');
|
|
||||||
}
|
|
||||||
*m_writep ++= ' '; printCode(code); *m_writep ++= '\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
|
|
||||||
m_sigs_oldvalp[code] = newval;
|
|
||||||
m_sigs_oldvalp[code+1] = newtri;
|
|
||||||
*m_writep++ = "01zz"[m_sigs_oldvalp[code]
|
|
||||||
| (m_sigs_oldvalp[code+1]<<1)];
|
|
||||||
printCode(code); *m_writep++='\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) {
|
|
||||||
m_sigs_oldvalp[code] = newval;
|
|
||||||
m_sigs_oldvalp[code+1] = newtri;
|
|
||||||
*m_writep++='b';
|
|
||||||
for (int bit=bits-1; bit>=0; --bit) {
|
|
||||||
*m_writep++ = "01zz"[((newval >> bit)&1)
|
|
||||||
| (((newtri >> bit)&1)<<1)];
|
|
||||||
}
|
|
||||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
void fullTriQuad(vluint32_t code, const vluint64_t newval,
|
|
||||||
const vluint32_t newtri, int bits) {
|
|
||||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) = newval;
|
|
||||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code+1]))) = newtri;
|
|
||||||
*m_writep++='b';
|
|
||||||
for (int bit=bits-1; bit>=0; --bit) {
|
|
||||||
*m_writep++ = "01zz"[((newval >> bit) & VL_ULL(1))
|
|
||||||
| (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
|
|
||||||
}
|
|
||||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
void fullTriArray(vluint32_t code, const vluint32_t* newvalp,
|
|
||||||
const vluint32_t* newtrip, int bits) {
|
|
||||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
|
||||||
m_sigs_oldvalp[code+word*2] = newvalp[word];
|
|
||||||
m_sigs_oldvalp[code+word*2+1] = newtrip[word];
|
|
||||||
}
|
|
||||||
*m_writep++='b';
|
|
||||||
for (int bit=bits-1; bit>=0; --bit) {
|
|
||||||
vluint32_t valbit = (newvalp[(bit/32)]>>(bit&0x1f)) & 1;
|
|
||||||
vluint32_t tribit = (newtrip[(bit/32)]>>(bit&0x1f)) & 1;
|
|
||||||
*m_writep++ = "01zz"[valbit | (tribit<<1)];
|
|
||||||
}
|
|
||||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
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
|
/// Inside dumping routines, dump one signal if it has changed.
|
||||||
/// Presently this code doesn't change the oldval vector.
|
/// We do want to inline these to avoid calls when the value did not change.
|
||||||
/// Thus this is for special standalone applications that after calling
|
|
||||||
/// fullBitX, must when then value goes non-X call fullBit.
|
|
||||||
inline void fullBitX(vluint32_t code) {
|
|
||||||
*m_writep++='x'; printCode(code); *m_writep++='\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
inline void fullBusX(vluint32_t code, int bits) {
|
|
||||||
*m_writep++='b';
|
|
||||||
for (int bit=bits-1; bit>=0; --bit) {
|
|
||||||
*m_writep++='x';
|
|
||||||
}
|
|
||||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
|
||||||
bufferCheck();
|
|
||||||
}
|
|
||||||
inline void fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); }
|
|
||||||
inline void fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); }
|
|
||||||
|
|
||||||
/// Inside dumping routines, dump one signal if it has changed
|
|
||||||
inline void chgBit(vluint32_t code, const vluint32_t newval) {
|
inline void chgBit(vluint32_t code, const vluint32_t newval) {
|
||||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
vluint32_t diff = oldp(code)[0] ^ newval;
|
||||||
if (VL_UNLIKELY(diff)) {
|
if (VL_UNLIKELY(diff)) fullBit(code, newval);
|
||||||
// Verilator 3.510 and newer provide clean input, so the below
|
|
||||||
// is only for back compatibility
|
|
||||||
if (VL_UNLIKELY(diff & 1)) { // Change after clean?
|
|
||||||
fullBit(code, newval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
|
inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
vluint32_t diff = oldp(code)[0] ^ newval;
|
||||||
if (VL_UNLIKELY(diff)) {
|
if (VL_UNLIKELY(diff)) {
|
||||||
if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
|
if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
|
||||||
fullBus(code, newval, bits);
|
fullBus(code, newval, bits);
|
||||||
@@ -347,33 +244,32 @@ 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*>(&m_sigs_oldvalp[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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void chgArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) {
|
||||||
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
||||||
if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newval[word])) {
|
if (VL_UNLIKELY(oldp(code)[word] ^ newvalp[word])) {
|
||||||
fullArray(code, newval, bits);
|
fullArray(code, newvalp, bits);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void chgArray(vluint32_t code, const vluint64_t* newval, int bits) {
|
inline void chgArray(vluint32_t code, const vluint64_t* newvalp, int bits) {
|
||||||
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) {
|
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) {
|
||||||
if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newval[word])) {
|
if (VL_UNLIKELY(*(reinterpret_cast<vluint64_t*>(oldp(code + 2 * word)))
|
||||||
fullArray(code, newval, bits);
|
^ newvalp[word])) {
|
||||||
|
fullArray(code, newvalp, bits);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void chgTriBit(vluint32_t code, const vluint32_t newval,
|
inline void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
|
||||||
const vluint32_t newtri) {
|
vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri));
|
||||||
vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval)
|
|
||||||
| (m_sigs_oldvalp[code+1] ^ newtri));
|
|
||||||
if (VL_UNLIKELY(diff)) {
|
if (VL_UNLIKELY(diff)) {
|
||||||
// Verilator 3.510 and newer provide clean input, so the below
|
// Verilator 3.510 and newer provide clean input, so the below
|
||||||
// is only for back compatibility
|
// is only for back compatibility
|
||||||
@@ -382,54 +278,55 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void chgTriBus(vluint32_t code, const vluint32_t newval,
|
inline void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri,
|
||||||
const vluint32_t newtri, int bits) {
|
int bits) {
|
||||||
vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval)
|
vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri));
|
||||||
| (m_sigs_oldvalp[code+1] ^ newtri));
|
|
||||||
if (VL_UNLIKELY(diff)) {
|
if (VL_UNLIKELY(diff)) {
|
||||||
if (VL_UNLIKELY(bits==32 || (diff & ((1U<<bits)-1) ))) {
|
if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
|
||||||
fullTriBus(code, newval, newtri, bits);
|
fullTriBus(code, newval, newtri, bits);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void chgTriQuad(vluint32_t code, const vluint64_t newval,
|
inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
|
||||||
const vluint32_t newtri, int bits) {
|
int bits) {
|
||||||
vluint64_t diff = ( ((*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) ^ newval)
|
vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
|
||||||
| ((*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp,
|
inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
|
||||||
const vluint32_t* newtrip, int bits) {
|
int bits) {
|
||||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
||||||
if (VL_UNLIKELY((m_sigs_oldvalp[code+word*2] ^ newvalp[word])
|
if (VL_UNLIKELY((oldp(code)[word * 2] ^ newvalp[word])
|
||||||
| (m_sigs_oldvalp[code+word*2+1] ^ newtrip[word]))) {
|
| (oldp(code)[word * 2 + 1] ^ newtrip[word]))) {
|
||||||
fullTriArray(code,newvalp,newtrip,bits);
|
fullTriArray(code, newvalp, newtrip, bits);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void chgDouble(vluint32_t code, const double newval) {
|
inline void chgDouble(vluint32_t code, const double newval) {
|
||||||
// cppcheck-suppress invalidPointerCast
|
// cppcheck-suppress invalidPointerCast
|
||||||
if (VL_UNLIKELY((*(reinterpret_cast<double*>(&m_sigs_oldvalp[code]))) != newval)) {
|
if (VL_UNLIKELY((*(reinterpret_cast<double*>(oldp(code)))) != newval)) {
|
||||||
fullDouble(code, newval);
|
fullDouble(code, newval);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inline void chgFloat(vluint32_t code, const float newval) {
|
|
||||||
// cppcheck-suppress invalidPointerCast
|
|
||||||
if (VL_UNLIKELY((*(reinterpret_cast<float*>(&m_sigs_oldvalp[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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Declare specializations here they are used in VerilatedVcdC just below
|
||||||
|
template <> void VerilatedTrace<VerilatedVcd>::dump(vluint64_t timeui);
|
||||||
|
template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const char* unitp);
|
||||||
|
template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const std::string& unit);
|
||||||
|
template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const char* unitp);
|
||||||
|
template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const std::string& unit);
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedVcdC
|
// VerilatedVcdC
|
||||||
/// Create a VCD dump file in C standalone (no SystemC) simulations.
|
/// Create a VCD dump file in C standalone (no SystemC) simulations.
|
||||||
@@ -441,12 +338,14 @@ class VerilatedVcdC {
|
|||||||
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedVcdC);
|
VL_UNCOPYABLE(VerilatedVcdC);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL)
|
explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL)
|
||||||
: m_sptrace(filep) {}
|
: m_sptrace(filep) {}
|
||||||
~VerilatedVcdC() { close(); }
|
~VerilatedVcdC() { close(); }
|
||||||
/// Routines can only be called from one thread; allow next call from different thread
|
/// Routines can only be called from one thread; allow next call from different thread
|
||||||
void changeThread() { spTrace()->changeThread(); }
|
void changeThread() { spTrace()->changeThread(); }
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
/// Is file open?
|
/// Is file open?
|
||||||
@@ -474,16 +373,25 @@ public:
|
|||||||
void dump(vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
void dump(vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||||
void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||||
/// Set time units (s/ms, defaults to ns)
|
/// Set time units (s/ms, defaults to ns)
|
||||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
/// For Verilated models, these propage from the Verilated default --timeunit
|
||||||
void set_time_unit(const char* unit) { m_sptrace.set_time_unit(unit); }
|
void set_time_unit(const char* unit) { m_sptrace.set_time_unit(unit); }
|
||||||
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
|
void set_time_unit(const std::string& unit) { m_sptrace.set_time_unit(unit); }
|
||||||
/// Set time resolution (s/ms, defaults to ns)
|
/// Set time resolution (s/ms, defaults to ns)
|
||||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
/// For Verilated models, these propage from the Verilated default --timeunit
|
||||||
void set_time_resolution(const char* unit) { m_sptrace.set_time_resolution(unit); }
|
void set_time_resolution(const char* unit) { m_sptrace.set_time_resolution(unit); }
|
||||||
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
|
void set_time_resolution(const std::string& unit) { m_sptrace.set_time_resolution(unit); }
|
||||||
|
|
||||||
/// 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
|
||||||
|
|||||||
@@ -25,21 +25,22 @@
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
#if (SYSTEMC_VERSION>=20050714)
|
#if (SYSTEMC_VERSION >= 20050714)
|
||||||
// SystemC 2.1.v1
|
// SystemC 2.1.v1
|
||||||
// cppcheck-suppress unusedFunction
|
// cppcheck-suppress unusedFunction
|
||||||
void VerilatedVcdSc::write_comment(const std::string &) {}
|
void VerilatedVcdSc::write_comment(const std::string&) {}
|
||||||
void VerilatedVcdSc::trace(const unsigned int &, const std::string &, const char**) {}
|
void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**) {}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
# define DECL_TRACE_METHOD_A(tp) \
|
# define DECL_TRACE_METHOD_A(tp) \
|
||||||
void VerilatedVcdSc::trace( const tp& object, const std::string& name ) {}
|
void VerilatedVcdSc::trace(const tp& object, const std::string& name) {}
|
||||||
# define DECL_TRACE_METHOD_B(tp) \
|
# define DECL_TRACE_METHOD_B(tp) \
|
||||||
void VerilatedVcdSc::trace( const tp& object, const std::string& name, int width ) {}
|
void VerilatedVcdSc::trace(const tp& object, const std::string& name, int width) {}
|
||||||
|
|
||||||
#if (SYSTEMC_VERSION>=20171012)
|
# if (SYSTEMC_VERSION >= 20171012)
|
||||||
DECL_TRACE_METHOD_A( sc_event )
|
DECL_TRACE_METHOD_A( sc_event )
|
||||||
DECL_TRACE_METHOD_A( sc_time )
|
DECL_TRACE_METHOD_A( sc_time )
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
DECL_TRACE_METHOD_A( bool )
|
DECL_TRACE_METHOD_A( bool )
|
||||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||||
@@ -49,9 +50,9 @@ void VerilatedVcdSc::trace(const unsigned int &, const std::string &, const char
|
|||||||
DECL_TRACE_METHOD_B( unsigned short )
|
DECL_TRACE_METHOD_B( unsigned short )
|
||||||
DECL_TRACE_METHOD_B( unsigned int )
|
DECL_TRACE_METHOD_B( unsigned int )
|
||||||
DECL_TRACE_METHOD_B( unsigned long )
|
DECL_TRACE_METHOD_B( unsigned long )
|
||||||
#ifdef SYSTEMC_64BIT_PATCHES
|
# ifdef SYSTEMC_64BIT_PATCHES
|
||||||
DECL_TRACE_METHOD_B( unsigned long long)
|
DECL_TRACE_METHOD_B( unsigned long long)
|
||||||
#endif
|
# endif
|
||||||
DECL_TRACE_METHOD_B( char )
|
DECL_TRACE_METHOD_B( char )
|
||||||
DECL_TRACE_METHOD_B( short )
|
DECL_TRACE_METHOD_B( short )
|
||||||
DECL_TRACE_METHOD_B( int )
|
DECL_TRACE_METHOD_B( int )
|
||||||
@@ -73,19 +74,21 @@ void VerilatedVcdSc::trace(const unsigned int &, const std::string &, const char
|
|||||||
|
|
||||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
#elif (SYSTEMC_VERSION>20011000)
|
#elif (SYSTEMC_VERSION > 20011000)
|
||||||
// SystemC 2.0.1
|
// SystemC 2.0.1
|
||||||
// cppcheck-suppress unusedFunction
|
// cppcheck-suppress unusedFunction
|
||||||
void VerilatedVcdSc::write_comment(const sc_string &) {}
|
void VerilatedVcdSc::write_comment(const sc_string&) {}
|
||||||
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
|
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
|
||||||
|
|
||||||
#define DECL_TRACE_METHOD_A(tp) \
|
#define DECL_TRACE_METHOD_A(tp) \
|
||||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {}
|
void VerilatedVcdSc::trace(const tp& object, const sc_string& name) {}
|
||||||
#define DECL_TRACE_METHOD_B(tp) \
|
#define DECL_TRACE_METHOD_B(tp) \
|
||||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {}
|
void VerilatedVcdSc::trace(const tp& object, const sc_string& name, int width) {}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
DECL_TRACE_METHOD_A( bool )
|
DECL_TRACE_METHOD_A( bool )
|
||||||
DECL_TRACE_METHOD_A( sc_bit )
|
DECL_TRACE_METHOD_A( sc_bit )
|
||||||
DECL_TRACE_METHOD_A( sc_logic )
|
DECL_TRACE_METHOD_A( sc_logic )
|
||||||
@@ -96,7 +99,7 @@ void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**)
|
|||||||
#ifdef SYSTEMC_64BIT_PATCHES
|
#ifdef SYSTEMC_64BIT_PATCHES
|
||||||
DECL_TRACE_METHOD_B( unsigned long long)
|
DECL_TRACE_METHOD_B( unsigned long long)
|
||||||
#endif
|
#endif
|
||||||
#if (SYSTEMC_VERSION>20041000)
|
#if (SYSTEMC_VERSION > 20041000)
|
||||||
DECL_TRACE_METHOD_B( unsigned long long)
|
DECL_TRACE_METHOD_B( unsigned long long)
|
||||||
DECL_TRACE_METHOD_B( long long)
|
DECL_TRACE_METHOD_B( long long)
|
||||||
#endif
|
#endif
|
||||||
@@ -116,19 +119,21 @@ void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**)
|
|||||||
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
||||||
DECL_TRACE_METHOD_A( sc_bv_base )
|
DECL_TRACE_METHOD_A( sc_bv_base )
|
||||||
DECL_TRACE_METHOD_A( sc_lv_base )
|
DECL_TRACE_METHOD_A( sc_lv_base )
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
#else
|
#else
|
||||||
// SystemC 1.2.1beta
|
// SystemC 1.2.1beta
|
||||||
// cppcheck-suppress unusedFunction
|
// cppcheck-suppress unusedFunction
|
||||||
void VerilatedVcdSc::write_comment(const sc_string &) {}
|
void VerilatedVcdSc::write_comment(const sc_string&) {}
|
||||||
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
|
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
|
||||||
|
|
||||||
#define DECL_TRACE_METHOD_A(tp) \
|
#define DECL_TRACE_METHOD_A(tp) \
|
||||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {}
|
void VerilatedVcdSc::trace(const tp& object, const sc_string& name) {}
|
||||||
#define DECL_TRACE_METHOD_B(tp) \
|
#define DECL_TRACE_METHOD_B(tp) \
|
||||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {}
|
void VerilatedVcdSc::trace(const tp& object, const sc_string& name, int width) {}
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
DECL_TRACE_METHOD_A( bool )
|
DECL_TRACE_METHOD_A( bool )
|
||||||
DECL_TRACE_METHOD_B( unsigned char )
|
DECL_TRACE_METHOD_B( unsigned char )
|
||||||
DECL_TRACE_METHOD_B( short unsigned int )
|
DECL_TRACE_METHOD_B( short unsigned int )
|
||||||
@@ -154,6 +159,7 @@ void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**)
|
|||||||
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
|
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
|
||||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
||||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
||||||
|
// clang-format on
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#undef DECL_TRACE_METHOD_A
|
#undef DECL_TRACE_METHOD_A
|
||||||
|
|||||||
+36
-35
@@ -31,44 +31,42 @@
|
|||||||
/// This class is passed to the SystemC simulation kernel, just like a
|
/// This class is passed to the SystemC simulation kernel, just like a
|
||||||
/// documented SystemC trace format.
|
/// documented SystemC trace format.
|
||||||
|
|
||||||
class VerilatedVcdSc
|
class VerilatedVcdSc : sc_trace_file, public VerilatedVcdC {
|
||||||
: sc_trace_file
|
|
||||||
, public VerilatedVcdC
|
|
||||||
{
|
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VL_UNCOPYABLE(VerilatedVcdSc);
|
VL_UNCOPYABLE(VerilatedVcdSc);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VerilatedVcdSc() {
|
VerilatedVcdSc() {
|
||||||
sc_get_curr_simcontext()->add_trace_file(this);
|
sc_get_curr_simcontext()->add_trace_file(this);
|
||||||
# if (SYSTEMC_VERSION>=20060505)
|
#if (SYSTEMC_VERSION >= 20060505)
|
||||||
// We want to avoid a depreciated warning, but still be back compatible.
|
// We want to avoid a depreciated warning, but still be back compatible.
|
||||||
// Turning off the message just for this still results in an
|
// Turning off the message just for this still results in an
|
||||||
// annoying "to turn off" message.
|
// annoying "to turn off" message.
|
||||||
sc_time t1sec(1,SC_SEC);
|
sc_time t1sec(1, SC_SEC);
|
||||||
if (t1sec.to_default_time_units()!=0) {
|
if (t1sec.to_default_time_units() != 0) {
|
||||||
sc_time tunits(1.0/t1sec.to_default_time_units(),SC_SEC);
|
sc_time tunits(1.0 / t1sec.to_default_time_units(), SC_SEC);
|
||||||
spTrace()->set_time_unit(tunits.to_string());
|
spTrace()->set_time_unit(tunits.to_string());
|
||||||
}
|
}
|
||||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||||
# elif (SYSTEMC_VERSION>20011000)
|
#elif (SYSTEMC_VERSION > 20011000)
|
||||||
// To confuse matters 2.1.beta returns a char* here, while 2.1.v1 returns a std::string
|
// To confuse matters 2.1.beta returns a char* here, while 2.1.v1 returns a std::string
|
||||||
// we allow both flavors with overloaded set_time_* functions.
|
// we allow both flavors with overloaded set_time_* functions.
|
||||||
spTrace()->set_time_unit(sc_get_default_time_unit().to_string());
|
spTrace()->set_time_unit(sc_get_default_time_unit().to_string());
|
||||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
virtual ~VerilatedVcdSc() { close(); }
|
virtual ~VerilatedVcdSc() { close(); }
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
/// Called by SystemC simulate()
|
/// Called by SystemC simulate()
|
||||||
virtual void cycle(bool delta_cycle) {
|
virtual void cycle(bool delta_cycle) {
|
||||||
# if (SYSTEMC_VERSION>20011000)
|
#if (SYSTEMC_VERSION > 20011000)
|
||||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||||
# else
|
#else
|
||||||
// VCD files must have integer timestamps, so we write all times in
|
// VCD files must have integer timestamps, so we write all times in
|
||||||
// increments of time_resolution
|
// increments of time_resolution
|
||||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||||
# endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@@ -78,26 +76,26 @@ private:
|
|||||||
// Cadence Incisive has these as abstract functions so we must create them
|
// Cadence Incisive has these as abstract functions so we must create them
|
||||||
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
|
||||||
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
# if (SYSTEMC_VERSION>=20050714)
|
#if (SYSTEMC_VERSION >= 20050714)
|
||||||
// SystemC 2.1.v1
|
// SystemC 2.1.v1
|
||||||
# define DECL_TRACE_METHOD_A(tp) \
|
// clang-format off
|
||||||
virtual void trace(const tp& object, const std::string& name);
|
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name);
|
||||||
# define DECL_TRACE_METHOD_B(tp) \
|
# define DECL_TRACE_METHOD_B(tp) \
|
||||||
virtual void trace(const tp& object, const std::string& name, int width);
|
virtual void trace(const tp& object, const std::string& name, int width);
|
||||||
|
|
||||||
virtual void write_comment(const std::string&);
|
virtual void write_comment(const std::string&);
|
||||||
virtual void trace(const unsigned int&, const std::string&, const char**);
|
virtual void trace(const unsigned int&, const std::string&, const char**);
|
||||||
|
|
||||||
#if (SYSTEMC_VERSION>=20171012)
|
// Formatting matches that of sc_trace.h
|
||||||
|
# if (SYSTEMC_VERSION >= 20171012)
|
||||||
DECL_TRACE_METHOD_A( sc_event )
|
DECL_TRACE_METHOD_A( sc_event )
|
||||||
DECL_TRACE_METHOD_A( sc_time )
|
DECL_TRACE_METHOD_A( sc_time )
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
DECL_TRACE_METHOD_A( bool )
|
DECL_TRACE_METHOD_A( bool )
|
||||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||||
@@ -107,9 +105,9 @@ private:
|
|||||||
DECL_TRACE_METHOD_B( unsigned short )
|
DECL_TRACE_METHOD_B( unsigned short )
|
||||||
DECL_TRACE_METHOD_B( unsigned int )
|
DECL_TRACE_METHOD_B( unsigned int )
|
||||||
DECL_TRACE_METHOD_B( unsigned long )
|
DECL_TRACE_METHOD_B( unsigned long )
|
||||||
#ifdef SYSTEMC_64BIT_PATCHES
|
# ifdef SYSTEMC_64BIT_PATCHES
|
||||||
DECL_TRACE_METHOD_B( unsigned long long)
|
DECL_TRACE_METHOD_B( unsigned long long)
|
||||||
#endif
|
# endif
|
||||||
DECL_TRACE_METHOD_B( char )
|
DECL_TRACE_METHOD_B( char )
|
||||||
DECL_TRACE_METHOD_B( short )
|
DECL_TRACE_METHOD_B( short )
|
||||||
DECL_TRACE_METHOD_B( int )
|
DECL_TRACE_METHOD_B( int )
|
||||||
@@ -131,12 +129,13 @@ private:
|
|||||||
|
|
||||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
# elif (SYSTEMC_VERSION>20011000)
|
#elif (SYSTEMC_VERSION > 20011000)
|
||||||
// SystemC 2.0.1
|
// SystemC 2.0.1
|
||||||
# define DECL_TRACE_METHOD_A(tp) \
|
// clang-format off
|
||||||
virtual void trace(const tp& object, const sc_string& name);
|
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const sc_string& name);
|
||||||
# define DECL_TRACE_METHOD_B(tp) \
|
# define DECL_TRACE_METHOD_B(tp) \
|
||||||
virtual void trace(const tp& object, const sc_string& name, int width);
|
virtual void trace(const tp& object, const sc_string& name, int width);
|
||||||
|
|
||||||
@@ -152,13 +151,13 @@ private:
|
|||||||
DECL_TRACE_METHOD_B( unsigned short )
|
DECL_TRACE_METHOD_B( unsigned short )
|
||||||
DECL_TRACE_METHOD_B( unsigned int )
|
DECL_TRACE_METHOD_B( unsigned int )
|
||||||
DECL_TRACE_METHOD_B( unsigned long )
|
DECL_TRACE_METHOD_B( unsigned long )
|
||||||
#ifdef SYSTEMC_64BIT_PATCHES
|
# ifdef SYSTEMC_64BIT_PATCHES
|
||||||
DECL_TRACE_METHOD_B( unsigned long long)
|
DECL_TRACE_METHOD_B( unsigned long long)
|
||||||
#endif
|
# endif
|
||||||
#if (SYSTEMC_VERSION>20041000)
|
# if (SYSTEMC_VERSION > 20041000)
|
||||||
DECL_TRACE_METHOD_B( unsigned long long)
|
DECL_TRACE_METHOD_B( unsigned long long)
|
||||||
DECL_TRACE_METHOD_B( long long)
|
DECL_TRACE_METHOD_B( long long)
|
||||||
#endif
|
# endif
|
||||||
DECL_TRACE_METHOD_B( char )
|
DECL_TRACE_METHOD_B( char )
|
||||||
DECL_TRACE_METHOD_B( short )
|
DECL_TRACE_METHOD_B( short )
|
||||||
DECL_TRACE_METHOD_B( int )
|
DECL_TRACE_METHOD_B( int )
|
||||||
@@ -175,12 +174,13 @@ private:
|
|||||||
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
||||||
DECL_TRACE_METHOD_A( sc_bv_base )
|
DECL_TRACE_METHOD_A( sc_bv_base )
|
||||||
DECL_TRACE_METHOD_A( sc_lv_base )
|
DECL_TRACE_METHOD_A( sc_lv_base )
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
# else
|
#else
|
||||||
// SystemC 1.2.1beta
|
// SystemC 1.2.1beta
|
||||||
# define DECL_TRACE_METHOD_A(tp) \
|
// clang-format off
|
||||||
virtual void trace(const tp& object, const sc_string& name);
|
# define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const sc_string& name);
|
||||||
# define DECL_TRACE_METHOD_B(tp) \
|
# define DECL_TRACE_METHOD_B(tp) \
|
||||||
virtual void trace(const tp& object, const sc_string& name, int width);
|
virtual void trace(const tp& object, const sc_string& name, int width);
|
||||||
|
|
||||||
@@ -213,9 +213,10 @@ private:
|
|||||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
||||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
||||||
# endif
|
# endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
# undef DECL_TRACE_METHOD_A
|
#undef DECL_TRACE_METHOD_A
|
||||||
# undef DECL_TRACE_METHOD_B
|
#undef DECL_TRACE_METHOD_B
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
+405
-371
File diff suppressed because it is too large
Load Diff
+160
-133
@@ -22,99 +22,100 @@
|
|||||||
///
|
///
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
|
|
||||||
#ifndef _VERILATEDOS_H_
|
#ifndef _VERILATEDOS_H_
|
||||||
#define _VERILATEDOS_H_ 1 ///< Header Guard
|
#define _VERILATEDOS_H_ 1 ///< Header Guard
|
||||||
|
|
||||||
|
// Current clang-format versions botch #ifdef inclusion, so
|
||||||
|
// clang-format off
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Compiler pragma abstraction
|
// Compiler pragma abstraction
|
||||||
|
|
||||||
#ifdef __GNUC__
|
#ifdef __GNUC__
|
||||||
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
|
# define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment)))
|
||||||
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
|
# define VL_ATTR_ALWINLINE __attribute__((always_inline))
|
||||||
# define VL_ATTR_COLD __attribute__ ((cold))
|
# define VL_ATTR_COLD __attribute__((cold))
|
||||||
# define VL_ATTR_HOT __attribute__ ((hot))
|
# define VL_ATTR_HOT __attribute__((hot))
|
||||||
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
|
# define VL_ATTR_NORETURN __attribute__((noreturn))
|
||||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
|
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__((format(printf, (fmtArgNum), (fmtArgNum) + 1)))
|
||||||
# define VL_ATTR_PURE __attribute__ ((pure))
|
# define VL_ATTR_PURE __attribute__((pure))
|
||||||
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
# define VL_ATTR_UNUSED __attribute__((unused))
|
||||||
# define VL_FUNC __func__
|
# define VL_FUNC __func__
|
||||||
# if defined(__clang__) && defined(VL_THREADED)
|
# if defined(__clang__) && defined(VL_THREADED)
|
||||||
# define VL_ACQUIRE(...) __attribute__ ((acquire_capability(__VA_ARGS__)))
|
# define VL_ACQUIRE(...) __attribute__((acquire_capability(__VA_ARGS__)))
|
||||||
# define VL_ACQUIRE_SHARED(...) __attribute__ ((acquire_shared_capability(__VA_ARGS__)))
|
# define VL_ACQUIRE_SHARED(...) __attribute__((acquire_shared_capability(__VA_ARGS__)))
|
||||||
# define VL_RELEASE(...) __attribute__ ((release_capability(__VA_ARGS__)))
|
# define VL_RELEASE(...) __attribute__((release_capability(__VA_ARGS__)))
|
||||||
# define VL_RELEASE_SHARED(...) __attribute__ ((release_shared_capability(__VA_ARGS__)))
|
# define VL_RELEASE_SHARED(...) __attribute__((release_shared_capability(__VA_ARGS__)))
|
||||||
# define VL_TRY_ACQUIRE(...) __attribute__ ((try_acquire_capability(__VA_ARGS__)))
|
# define VL_TRY_ACQUIRE(...) __attribute__((try_acquire_capability(__VA_ARGS__)))
|
||||||
# define VL_TRY_ACQUIRE_SHARED(...) __attribute__ ((try_acquire_shared_capability(__VA_ARGS__)))
|
# define VL_TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__)))
|
||||||
# define VL_CAPABILITY(x) __attribute__ ((capability(x)))
|
# define VL_CAPABILITY(x) __attribute__((capability(x)))
|
||||||
# define VL_REQUIRES(x) __attribute__ ((requires_capability(x)))
|
# define VL_REQUIRES(x) __attribute__((requires_capability(x)))
|
||||||
# define VL_GUARDED_BY(x) __attribute__ ((guarded_by(x)))
|
# define VL_GUARDED_BY(x) __attribute__((guarded_by(x)))
|
||||||
# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x)))
|
# define VL_EXCLUDES(x) __attribute__((locks_excluded(x)))
|
||||||
# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable))
|
# define VL_SCOPED_CAPABILITY __attribute__((scoped_lockable))
|
||||||
# endif
|
# endif
|
||||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||||
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||||
# define VL_UNREACHABLE __builtin_unreachable();
|
# define VL_UNREACHABLE __builtin_unreachable();
|
||||||
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
|
# define VL_PREFETCH_RD(p) __builtin_prefetch((p), 0)
|
||||||
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
|
# define VL_PREFETCH_RW(p) __builtin_prefetch((p), 1)
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
# define VL_FUNC __FUNCTION__
|
# define VL_FUNC __FUNCTION__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Defaults for unsupported compiler features
|
// Defaults for unsupported compiler features
|
||||||
#ifndef VL_ATTR_ALIGNED
|
#ifndef VL_ATTR_ALIGNED
|
||||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_ALWINLINE
|
#ifndef VL_ATTR_ALWINLINE
|
||||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_COLD
|
#ifndef VL_ATTR_COLD
|
||||||
# define VL_ATTR_COLD ///< Function is rarely executed
|
# define VL_ATTR_COLD ///< Function is rarely executed
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_HOT
|
#ifndef VL_ATTR_HOT
|
||||||
# define VL_ATTR_HOT ///< Function is highly executed
|
# define VL_ATTR_HOT ///< Function is highly executed
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_NORETURN
|
#ifndef VL_ATTR_NORETURN
|
||||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_PRINTF
|
#ifndef VL_ATTR_PRINTF
|
||||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_PURE
|
#ifndef VL_ATTR_PURE
|
||||||
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_ATTR_UNUSED
|
#ifndef VL_ATTR_UNUSED
|
||||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_FUNC
|
#ifndef VL_FUNC
|
||||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_CAPABILITY
|
#ifndef VL_CAPABILITY
|
||||||
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
||||||
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
||||||
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
||||||
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
||||||
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
||||||
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
|
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired shared (-fthread-safety)
|
||||||
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
||||||
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
||||||
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
||||||
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
||||||
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_LIKELY
|
#ifndef VL_LIKELY
|
||||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||||
#endif
|
#endif
|
||||||
#define VL_UNCOVERABLE(x) VL_UNLIKELY(x) ///< Boolean expression never hit by users (no coverage)
|
# define VL_UNCOVERABLE(x) VL_UNLIKELY(x) ///< Boolean expression never hit by users (no coverage)
|
||||||
#ifndef VL_UNREACHABLE
|
#ifndef VL_UNREACHABLE
|
||||||
# define VL_UNREACHABLE ///< Point that may never be reached
|
# define VL_UNREACHABLE ///< Point that may never be reached
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_PREFETCH_RD
|
#ifndef VL_PREFETCH_RD
|
||||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||||
#endif
|
#endif
|
||||||
#ifndef VL_PREFETCH_RW
|
#ifndef VL_PREFETCH_RW
|
||||||
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef VL_THREADED
|
#ifdef VL_THREADED
|
||||||
@@ -122,45 +123,44 @@
|
|||||||
# define VL_THREAD_LOCAL thread_local
|
# define VL_THREAD_LOCAL thread_local
|
||||||
# elif defined(__GNUC__)
|
# elif defined(__GNUC__)
|
||||||
# if (__cplusplus < 201103L) && !defined(VL_THREADED_NO_C11_WARNING)
|
# if (__cplusplus < 201103L) && !defined(VL_THREADED_NO_C11_WARNING)
|
||||||
# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler"
|
# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler"
|
||||||
# endif
|
# endif
|
||||||
# else
|
# else
|
||||||
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
|
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
|
||||||
# endif
|
# endif
|
||||||
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
||||||
#else
|
#else
|
||||||
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
||||||
#endif
|
#endif
|
||||||
#define VL_THREAD ///< Deprecated
|
|
||||||
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
#define VL_THREAD ///< Deprecated
|
||||||
|
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||||
|
|
||||||
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||||
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
||||||
#define VL_MT_SAFE_POSTINIT ///< Comment tag that function is threadsafe when VL_THREADED, only during normal operation (post-init)
|
#define VL_MT_SAFE_POSTINIT ///< Comment tag that function is threadsafe when VL_THREADED, only
|
||||||
|
///< during normal operation (post-init)
|
||||||
#define VL_MT_UNSAFE ///< Comment tag that function is not threadsafe when VL_THREADED
|
#define VL_MT_UNSAFE ///< 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
|
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
|
||||||
|
///< protected to make sure single-caller
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated)
|
||||||
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
|
|
||||||
#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 { \
|
||||||
@@ -169,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 { \
|
||||||
@@ -198,6 +198,7 @@
|
|||||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||||
# endif
|
# endif
|
||||||
# define VL_FINAL final
|
# define VL_FINAL final
|
||||||
|
# define VL_MUTABLE mutable
|
||||||
# define VL_OVERRIDE override
|
# define VL_OVERRIDE override
|
||||||
#else
|
#else
|
||||||
# define VL_EQ_DELETE
|
# define VL_EQ_DELETE
|
||||||
@@ -205,6 +206,7 @@
|
|||||||
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
|
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
|
||||||
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
|
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
|
||||||
# define VL_FINAL
|
# define VL_FINAL
|
||||||
|
# define VL_MUTABLE
|
||||||
# define VL_OVERRIDE
|
# define VL_OVERRIDE
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -215,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
|
||||||
|
|
||||||
@@ -247,47 +263,47 @@
|
|||||||
# include <stdint.h>
|
# include <stdint.h>
|
||||||
# include <sys/types.h> // __WORDSIZE
|
# include <sys/types.h> // __WORDSIZE
|
||||||
# include <unistd.h> // ssize_t
|
# include <unistd.h> // ssize_t
|
||||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||||
typedef char vlsint8_t; ///< 8-bit signed type
|
typedef char vlsint8_t; ///< 8-bit signed type
|
||||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||||
typedef short int vlsint16_t; ///< 16-bit signed type
|
typedef short int vlsint16_t; ///< 16-bit signed type
|
||||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||||
# if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int
|
# if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int
|
||||||
typedef int32_t vlsint32_t; ///< 32-bit signed type
|
typedef int32_t vlsint32_t; ///< 32-bit signed type
|
||||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||||
# else // Older Cygwin has long==uint32_t
|
# else // Older Cygwin has long==uint32_t
|
||||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||||
typedef long vlsint32_t; ///< 32-bit signed type
|
typedef long vlsint32_t; ///< 32-bit signed type
|
||||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||||
# endif
|
# endif
|
||||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||||
typedef long vlsint64_t; ///< 64-bit signed type
|
typedef long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||||
# else
|
# else
|
||||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
#elif defined(_WIN32) && defined(_MSC_VER)
|
#elif defined(_WIN32) && defined(_MSC_VER)
|
||||||
|
|
||||||
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||||
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||||
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||||
typedef signed __int8 vlsint8_t; ///< 8-bit signed type
|
typedef signed __int8 vlsint8_t; ///< 8-bit signed type
|
||||||
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
||||||
typedef signed __int16 vlsint16_t; ///< 16-bit signed type
|
typedef signed __int16 vlsint16_t; ///< 16-bit signed type
|
||||||
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
||||||
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
||||||
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
||||||
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||||
|
|
||||||
# ifndef _SSIZE_T_DEFINED
|
# ifndef _SSIZE_T_DEFINED
|
||||||
# ifdef _WIN64
|
# ifdef _WIN64
|
||||||
typedef signed __int64 ssize_t; ///< signed size_t; returned from read()
|
typedef signed __int64 ssize_t; ///< signed size_t; returned from read()
|
||||||
# else
|
# else
|
||||||
typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
|
typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
|
||||||
# endif
|
# endif
|
||||||
# endif
|
# endif
|
||||||
|
|
||||||
@@ -297,18 +313,18 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro
|
|||||||
# include <stdint.h> // Linux and most flavors
|
# include <stdint.h> // Linux and most flavors
|
||||||
# include <sys/types.h> // __WORDSIZE
|
# include <sys/types.h> // __WORDSIZE
|
||||||
# include <unistd.h> // ssize_t
|
# include <unistd.h> // ssize_t
|
||||||
typedef char vlsint8_t; ///< 8-bit signed type
|
typedef char vlsint8_t; ///< 8-bit signed type
|
||||||
typedef uint8_t vluint8_t; ///< 8-bit unsigned type
|
typedef uint8_t vluint8_t; ///< 8-bit unsigned type
|
||||||
typedef short vlsint16_t; ///< 16-bit signed type
|
typedef short vlsint16_t; ///< 16-bit signed type
|
||||||
typedef uint16_t vluint16_t; ///< 16-bit unsigned type
|
typedef uint16_t vluint16_t; ///< 16-bit unsigned type
|
||||||
typedef int vlsint32_t; ///< 32-bit signed type
|
typedef int vlsint32_t; ///< 32-bit signed type
|
||||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||||
typedef long vlsint64_t; ///< 64-bit signed type
|
typedef long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||||
# else
|
# else
|
||||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||||
# endif
|
# endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -351,14 +367,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Integer size macros
|
// Integer size macros
|
||||||
|
|
||||||
#define VL_BYTESIZE 8 ///< Bits in a CData / byte
|
#define VL_BYTESIZE 8 ///< Bits in a CData / byte
|
||||||
#define VL_SHORTSIZE 16 ///< Bits in a SData / short
|
#define VL_SHORTSIZE 16 ///< Bits in a SData / short
|
||||||
#define VL_IDATASIZE 32 ///< Bits in a IData / word
|
#define VL_IDATASIZE 32 ///< Bits in a IData / word
|
||||||
#define VL_WORDSIZE IDATASIZE ///< Legacy define
|
#define VL_WORDSIZE VL_IDATASIZE ///< Legacy define
|
||||||
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
|
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
|
||||||
#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry)
|
#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry)
|
||||||
#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE)
|
#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE)
|
||||||
#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment)
|
#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment)
|
||||||
|
|
||||||
/// Bytes this number of bits needs (1 bit=1 byte)
|
/// Bytes this number of bits needs (1 bit=1 byte)
|
||||||
#define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE)
|
#define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE)
|
||||||
@@ -371,15 +387,15 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
// Class definition helpers
|
// Class definition helpers
|
||||||
|
|
||||||
// Used to declare a class as uncopyable; put after a private:
|
// Used to declare a class as uncopyable; put after a private:
|
||||||
#define VL_UNCOPYABLE(Type) \
|
#define VL_UNCOPYABLE(Type) \
|
||||||
Type(const Type& other) VL_EQ_DELETE; \
|
Type(const Type& other) VL_EQ_DELETE; \
|
||||||
Type& operator= (const Type&) VL_EQ_DELETE
|
Type& operator=(const Type&) VL_EQ_DELETE
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Verilated function size macros
|
// Verilated function size macros
|
||||||
|
|
||||||
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
|
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
|
||||||
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Base macros
|
// Base macros
|
||||||
@@ -389,11 +405,10 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
#define VL_SIZEBITS_E (VL_EDATASIZE - 1) ///< Bit mask for bits in a quad
|
#define VL_SIZEBITS_E (VL_EDATASIZE - 1) ///< Bit mask for bits in a quad
|
||||||
|
|
||||||
/// Mask for words with 1's where relevant bits are (0=all bits)
|
/// Mask for words with 1's where relevant bits are (0=all bits)
|
||||||
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) \
|
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0)
|
||||||
? ((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) (((nbits) & VL_SIZEBITS_Q) \
|
#define VL_MASK_Q(nbits) \
|
||||||
? ((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
|
||||||
@@ -409,8 +424,8 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
// #defines, to avoid requiring math.h on all compile runs
|
// #defines, to avoid requiring math.h on all compile runs
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
# define VL_TRUNC(n) (((n)<0) ? ceil((n)) : floor((n)))
|
# define VL_TRUNC(n) (((n) < 0) ? ceil((n)) : floor((n)))
|
||||||
# define VL_ROUND(n) (((n)<0) ? ceil((n)-0.5) : floor((n)+0.5))
|
# define VL_ROUND(n) (((n) < 0) ? ceil((n)-0.5) : floor((n) + 0.5))
|
||||||
#else
|
#else
|
||||||
# define VL_TRUNC(n) trunc(n)
|
# define VL_TRUNC(n) trunc(n)
|
||||||
# define VL_ROUND(n) round(n)
|
# define VL_ROUND(n) round(n)
|
||||||
@@ -422,13 +437,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
/// 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 implemeted on this platform
|
||||||
#if defined(__i386__) || defined(__x86_64__)
|
#if defined(__i386__) || defined(__x86_64__)
|
||||||
# define VL_RDTSC(val) { \
|
#define VL_RDTSC(val) \
|
||||||
vluint32_t hi, lo; \
|
{ \
|
||||||
asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); \
|
vluint32_t hi, lo; \
|
||||||
(val) = ((vluint64_t)lo) | (((vluint64_t)hi)<<32); \
|
asm volatile("rdtsc" : "=a"(lo), "=d"(hi)); \
|
||||||
}
|
(val) = ((vluint64_t)lo) | (((vluint64_t)hi) << 32); \
|
||||||
|
}
|
||||||
#elif defined(__aarch64__)
|
#elif defined(__aarch64__)
|
||||||
# define VL_RDTSC(val) asm volatile("mrs %[rt],PMCCNTR_EL0" : [rt] "=r" (val));
|
# define VL_RDTSC(val) asm volatile("mrs %[rt],PMCCNTR_EL0" : [rt] "=r"(val));
|
||||||
#else
|
#else
|
||||||
// We just silently ignore unknown OSes, as only leads to missing statistics
|
// We just silently ignore unknown OSes, as only leads to missing statistics
|
||||||
# define VL_RDTSC(val) (val) = 0;
|
# define VL_RDTSC(val) (val) = 0;
|
||||||
@@ -467,6 +483,17 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
|||||||
# define VL_STRCASECMP strcasecmp
|
# define VL_STRCASECMP strcasecmp
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// Macros controlling target specific optimizations
|
||||||
|
|
||||||
|
// Define VL_PORTABLE_ONLY to disable all target specific optimizations
|
||||||
|
#ifndef VL_PORTABLE_ONLY
|
||||||
|
# ifdef __x86_64__
|
||||||
|
# define VL_X86_64 1
|
||||||
|
# endif
|
||||||
|
#endif // VL_PORTABLE_ONLY
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Stringify macros
|
// Stringify macros
|
||||||
|
|
||||||
|
|||||||
@@ -1,58 +0,0 @@
|
|||||||
#!/usr/bin/env perl
|
|
||||||
######################################################################
|
|
||||||
#
|
|
||||||
# Copyright 2007-2020 by Wilson Snyder. This program is free software; you
|
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
|
||||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
|
||||||
# Version 2.0.
|
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
#
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
# DESCRIPTION: Debugging of bison output
|
|
||||||
|
|
||||||
use warnings;
|
|
||||||
use strict;
|
|
||||||
|
|
||||||
my $Debug;
|
|
||||||
|
|
||||||
my %declared;
|
|
||||||
my %used;
|
|
||||||
|
|
||||||
my $body = 0;
|
|
||||||
my $rule = "";
|
|
||||||
my $lineno = 0;
|
|
||||||
foreach my $line (<STDIN>) {
|
|
||||||
$lineno++;
|
|
||||||
chomp $line;
|
|
||||||
$line =~ s!//.*$!!g;
|
|
||||||
$line =~ s!\s+! !g;
|
|
||||||
next if $line eq '';
|
|
||||||
if ($line =~ m!^\%\%!) {
|
|
||||||
$body++;
|
|
||||||
} elsif ($body == 1) {
|
|
||||||
$rule .= $line;
|
|
||||||
if ($line =~ m!^\s*;\s*$!) {
|
|
||||||
#print "Rule: $rule\n";
|
|
||||||
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
|
|
||||||
my $rulename = $1; my $preaction = $3;
|
|
||||||
$declared{$rulename} = $lineno;
|
|
||||||
$preaction =~ s/\{[^\}]*\}/ /g;
|
|
||||||
#print "RULEN $rulename PA $preaction\n" if $Debug;
|
|
||||||
$rule = '';
|
|
||||||
foreach my $ref (split /\s+/, $preaction) {
|
|
||||||
next if $ref !~ /^[a-zA-Z]/;
|
|
||||||
next if $ref eq $rulename;
|
|
||||||
if (!$used{$ref} && $declared{$ref}) {
|
|
||||||
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
|
|
||||||
}
|
|
||||||
$used{$ref} = $lineno;
|
|
||||||
print " ref $ref\n" if $Debug;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
# Local Variables:
|
|
||||||
# compile-command: "./bisonreader < ../src/verilog.y"
|
|
||||||
# End:
|
|
||||||
+302
-57
@@ -6,30 +6,71 @@ use warnings;
|
|||||||
use Cwd;
|
use Cwd;
|
||||||
use File::Copy qw(cp);
|
use File::Copy qw(cp);
|
||||||
use File::Path qw(mkpath);
|
use File::Path qw(mkpath);
|
||||||
|
use File::Spec;
|
||||||
|
use FindBin qw($RealBin);
|
||||||
use Getopt::Long;
|
use Getopt::Long;
|
||||||
|
use Parallel::Forker;
|
||||||
|
use Unix::Processors;
|
||||||
use IO::File;
|
use IO::File;
|
||||||
use Pod::Usage;
|
use Pod::Usage;
|
||||||
use strict;
|
use strict;
|
||||||
use vars qw($Debug);
|
use vars qw($Debug);
|
||||||
|
|
||||||
|
our $Opt_Stop = 1;
|
||||||
|
our $Opt_Fastcov = 1;
|
||||||
|
our $Exclude_Branch_Regexp;
|
||||||
our $Exclude_Line_Regexp;
|
our $Exclude_Line_Regexp;
|
||||||
|
our $Remove_Gcda_Regexp;
|
||||||
|
|
||||||
our @Remove_Sources;
|
our @Remove_Sources;
|
||||||
our @Source_Globs;
|
our @Source_Globs;
|
||||||
|
|
||||||
|
our $Fork = new Parallel::Forker(use_sig_child => 1, poll_interval => 10*1000);
|
||||||
|
$Fork->max_proc(Unix::Processors->new->max_online * 1.5);
|
||||||
|
$SIG{CHLD} = sub { Parallel::Forker::sig_child($Fork); };
|
||||||
|
$SIG{TERM} = sub { $Fork->kill_tree_all('TERM') if $Fork && $Fork->in_parent; die "Quitting...\n"; };
|
||||||
|
|
||||||
#======================================================================
|
#======================================================================
|
||||||
# main
|
# main
|
||||||
|
|
||||||
our $Opt_Stage = 0;
|
our $Opt_Hashset;
|
||||||
|
our $opt_stages = '';
|
||||||
|
our $Opt_Scenarios;
|
||||||
|
our %Opt_Stages;
|
||||||
|
our @Opt_Tests;
|
||||||
|
|
||||||
autoflush STDOUT 1;
|
autoflush STDOUT 1;
|
||||||
autoflush STDERR 1;
|
autoflush STDERR 1;
|
||||||
Getopt::Long::config("no_auto_abbrev");
|
Getopt::Long::config("no_auto_abbrev");
|
||||||
if (! GetOptions(
|
if (! GetOptions(
|
||||||
"debug" => sub { $Debug = 1; },
|
"debug" => sub { $Debug = 1; },
|
||||||
|
"hashset=s" => \$Opt_Hashset, # driver.pl hashset
|
||||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||||
"stage=i" => \$Opt_Stage,
|
"fastcov!" => \$Opt_Fastcov, # use fastcov, not documented, for debug
|
||||||
|
"scenarios=s" => \$Opt_Scenarios, # driver.pl scenarios
|
||||||
|
"stage=s" => \$opt_stages, # starting stage number
|
||||||
|
"stages=s" => \$opt_stages, # starting stage number
|
||||||
|
"stop!" => \$Opt_Stop, # stop/do not stop on error in tests
|
||||||
|
"test=s@" => \@Opt_Tests, # test name
|
||||||
)) {
|
)) {
|
||||||
die "%Error: Bad usage, try 'install_test --help'\n";
|
die "%Error: Bad usage, try 'code_coverage --help'\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
my $start = 0;
|
||||||
|
my $end = 99;
|
||||||
|
if ($opt_stages && $opt_stages =~ /^(\d+)$/) {
|
||||||
|
$start = $end = $1;
|
||||||
|
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-(\d+$)$/) {
|
||||||
|
$start = $1; $end = $2;
|
||||||
|
} elsif ($opt_stages && $opt_stages =~ /^-(\d+$)$/) {
|
||||||
|
$end = $1;
|
||||||
|
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-$/) {
|
||||||
|
$start = $1;
|
||||||
|
} elsif ($opt_stages) {
|
||||||
|
die "%Error: --stages not understood: $opt_stages,";
|
||||||
|
}
|
||||||
|
for (my $n = $start; $n <= $end; ++$n) { $Opt_Stages{$n} = 1; }
|
||||||
}
|
}
|
||||||
|
|
||||||
test();
|
test();
|
||||||
@@ -41,97 +82,238 @@ sub test {
|
|||||||
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
|
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
|
||||||
require "./nodist/code_coverage.dat";
|
require "./nodist/code_coverage.dat";
|
||||||
|
|
||||||
if ($Opt_Stage <= 0) {
|
if ($Opt_Stages{1}) {
|
||||||
print "Stage 0: configure (coverage on)\n";
|
travis_fold_start("configure");
|
||||||
run("make distclean");
|
print "Stage 1: configure (coverage on)\n";
|
||||||
run("./configure --enable-longtests CXX='g++ --coverage'");
|
run("make distclean || true");
|
||||||
run("make -k");
|
run("autoconf");
|
||||||
|
# Exceptions can pollute the branch coverage data
|
||||||
|
run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'");
|
||||||
|
travis_fold_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Opt_Stages{2}) {
|
||||||
|
travis_fold_start("build");
|
||||||
|
print "Stage 2: build\n";
|
||||||
|
my $nproc = Unix::Processors->new->max_online;
|
||||||
|
run("make -k -j $nproc VERILATOR_NO_OPT_BUILD=1");
|
||||||
# The optimized versions will not collect good coverage, overwrite them
|
# The optimized versions will not collect good coverage, overwrite them
|
||||||
run("cp bin/verilator_bin_dbg bin/verilator_bin");
|
run("cp bin/verilator_bin_dbg bin/verilator_bin");
|
||||||
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
|
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 1) {
|
if ($Opt_Stages{3}) {
|
||||||
print "Stage 1: make examples (with coverage on)\n";
|
travis_fold_start("test");
|
||||||
run("make examples");
|
print "Stage 3: make tests (with coverage on)\n";
|
||||||
run("make test_regress");
|
if ($#Opt_Tests < 0) {
|
||||||
|
run("make examples VERILATOR_NO_OPT_BUILD=1")
|
||||||
|
if !$Opt_Scenarios || $Opt_Scenarios =~ /dist/i;
|
||||||
|
run("make test_regress VERILATOR_NO_OPT_BUILD=1"
|
||||||
|
. ($Opt_Scenarios ? " SCENARIOS='".$Opt_Scenarios."'" : "")
|
||||||
|
. ($Opt_Hashset ? " DRIVER_HASHSET='--hashset=".$Opt_Hashset."'" : "")
|
||||||
|
. ($Opt_Stop ? '' : ' || true'));
|
||||||
|
} else {
|
||||||
|
foreach my $test (@Opt_Tests) {
|
||||||
|
if (! -f $test && -f "test_regress/t/${test}") {
|
||||||
|
$test = "test_regress/t/${test}";
|
||||||
|
}
|
||||||
|
run($test);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
my $cc_dir = "nodist/obj_dir/coverage";
|
my $cc_dir = "nodist/obj_dir/coverage";
|
||||||
if ($Opt_Stage <= 2) {
|
if ($Opt_Stages{4}) {
|
||||||
print "Stage 2: Create info files under $cc_dir\n";
|
travis_fold_start("gcno");
|
||||||
|
print "Stage 4: Create gcno files under $cc_dir\n";
|
||||||
mkpath($cc_dir);
|
mkpath($cc_dir);
|
||||||
mkpath("$cc_dir/info");
|
mkpath("$cc_dir/info");
|
||||||
my $dats = `find . -print | grep .gcda`;
|
my $dats = `find . -print | grep .gcda`;
|
||||||
|
my %dats;
|
||||||
|
foreach my $dat (split '\n', $dats) {
|
||||||
|
$dats{$dat} = 1;
|
||||||
|
}
|
||||||
|
foreach my $dat (sort keys %dats) {
|
||||||
|
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
|
||||||
|
if ($dat =~ /$Remove_Gcda_Regexp/) {
|
||||||
|
# Remove .gcda/.gcno for files we don't care about before we slowly
|
||||||
|
# read them
|
||||||
|
unlink $dat;
|
||||||
|
unlink $gcno;
|
||||||
|
delete $dats{$dat};
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$dats = `find . -print | grep .gcno`;
|
||||||
|
my %gcnos;
|
||||||
|
foreach my $gcno (split '\n', $dats) {
|
||||||
|
(my $gbase = $gcno) =~ s!.*/!!;
|
||||||
|
$gcnos{$gbase} = File::Spec->rel2abs($gcno);
|
||||||
|
}
|
||||||
|
# We need a matching .gcno for every .gcda, try to find a matching file elsewhere
|
||||||
|
foreach my $dat (sort keys %dats) {
|
||||||
|
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
|
||||||
|
(my $gbase = $gcno) =~ s!.*/!!;
|
||||||
|
if (!-r $gcno) {
|
||||||
|
if ($gcnos{$gbase}) {
|
||||||
|
symlink($gcnos{$gbase}, $gcno)
|
||||||
|
or die "%Error: can't ln -s $gcnos{$gbase} $gcno,";
|
||||||
|
} else {
|
||||||
|
warn "MISSING .gcno for a .gcda: $gcno\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
travis_fold_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Opt_Stages{5} && $Opt_Fastcov) {
|
||||||
|
travis_fold_start("fastcov");
|
||||||
|
# Must run in root directory to find all files
|
||||||
|
mkpath($cc_dir);
|
||||||
|
#run("${RealBin}/fastcov.py -b -c src/obj_dbg -X".
|
||||||
|
# " --exclude /usr --exclude test_regress"
|
||||||
|
# ." -o ${cc_dir}/app_total.json");
|
||||||
|
run("${RealBin}/fastcov.py -b -c src/obj_dbg -X --lcov".
|
||||||
|
" --exclude /usr --exclude test_regress"
|
||||||
|
." -o ${cc_dir}/app_total.info");
|
||||||
|
travis_fold_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Opt_Stages{5} && !$Opt_Fastcov) {
|
||||||
|
travis_fold_start("infos");
|
||||||
|
print "Stage 5: make infos\n";
|
||||||
|
my $dats = `find . -print | grep .gcda`;
|
||||||
my %dirs;
|
my %dirs;
|
||||||
foreach my $dat (split '\n', $dats) {
|
foreach my $dat (split '\n', $dats) {
|
||||||
$dat =~ s!/[^/]+$!!;
|
(my $dir = $dat) =~ s!/[^/]+$!!;
|
||||||
$dirs{$dat} = 1;
|
$dirs{$dir} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach my $dir (sort keys %dirs) {
|
foreach my $dir (sort keys %dirs) {
|
||||||
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
|
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
|
||||||
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir -o app_test_${outname}.info");
|
$Fork->schedule(run_on_start => sub {
|
||||||
|
# .info may be empty, so ignore errors (unfortunately)
|
||||||
|
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir --exclude /usr -o app_test_${outname}.info || true");
|
||||||
|
})->run;
|
||||||
}
|
}
|
||||||
|
$Fork->wait_all;
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 3) {
|
if ($Opt_Stages{6}) {
|
||||||
# lcov doesn't have a control file to override single lines, so replicate the sources
|
travis_fold_start("clone");
|
||||||
print "Stage 3: Clone sources under $cc_dir\n";
|
# No control file to override single lines, so replicate the sources
|
||||||
|
# Also lets us see the insertion markers in the HTML source res
|
||||||
|
print "Stage 6: Clone sources under $cc_dir\n";
|
||||||
clone_sources($cc_dir);
|
clone_sources($cc_dir);
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 4) {
|
if ($Opt_Stages{8} && !$Opt_Fastcov) {
|
||||||
print "Stage 4: Copy .gcno files\n";
|
travis_fold_start("copy");
|
||||||
|
print "Stage 8: Copy .gcno files\n";
|
||||||
my $dats = `find . -print | grep .gcno`;
|
my $dats = `find . -print | grep .gcno`;
|
||||||
foreach my $dat (split '\n', $dats) {
|
foreach my $dat (sort (split '\n', $dats)) {
|
||||||
next if $dat =~ /$cc_dir/;
|
next if $dat =~ /$cc_dir/;
|
||||||
my $outdat = $cc_dir."/".$dat;
|
my $outdat = $cc_dir."/".$dat;
|
||||||
#print "cp $dat, $outdat);\n";
|
#print "cp $dat, $outdat);\n";
|
||||||
cp($dat, $outdat);
|
cp($dat, $outdat);
|
||||||
}
|
}
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 5) {
|
if ($Opt_Stages{10} && !$Opt_Fastcov) {
|
||||||
print "Stage 5: Combine data files\n";
|
travis_fold_start("combine");
|
||||||
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
|
print "Stage 10: Combine data files\n";
|
||||||
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
|
{
|
||||||
my $infos = `cd $cc_dir ; find info -print | grep .info`;
|
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
|
||||||
my $comb = "";
|
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
|
||||||
my @infos = (split /\n/, $infos);
|
my $infos = `cd $cc_dir ; find info -print | grep .info`;
|
||||||
foreach my $info (@infos) {
|
my $comb = "";
|
||||||
$comb .= " -a $info";
|
my @infos = (sort (split /\n/, $infos));
|
||||||
# Need to batch them to avoid overrunning shell command length limit
|
foreach my $info (@infos) {
|
||||||
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
|
$comb .= " -a $info";
|
||||||
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info");
|
# Need to batch them to avoid overrunning shell command length limit
|
||||||
$comb = "";
|
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
|
||||||
|
# .info may be empty, so ignore errors (unfortunately)
|
||||||
|
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info || true");
|
||||||
|
$comb = "";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 6) {
|
if ($Opt_Stages{11}) {
|
||||||
print "Stage 6: Filter processed source files\n";
|
travis_fold_start("dirs");
|
||||||
my $cmd = '';
|
print "Stage 11: Cleanup paths\n";
|
||||||
foreach my $glob (@Remove_Sources) {
|
if ($Opt_Fastcov) {
|
||||||
$cmd .= " '$glob'";
|
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
||||||
|
#cleanup_abs_paths_json($cc_dir, "$cc_dir/app_total.json", "$cc_dir/app_total.json");
|
||||||
|
} else {
|
||||||
|
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
||||||
}
|
}
|
||||||
run("cd $cc_dir ; lcov --remove app_total.info $cmd -o app_total.info");
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 7) {
|
if ($Opt_Stages{12}) {
|
||||||
print "Stage 7: Create HTML\n";
|
travis_fold_start("filter");
|
||||||
cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
print "Stage 12: Filter processed source files\n";
|
||||||
run("cd $cc_dir ; genhtml app_total.info --demangle-cpp"
|
my $inc = '';
|
||||||
|
foreach my $glob (@Source_Globs) {
|
||||||
|
foreach my $infile (glob $glob) {
|
||||||
|
$inc .= " '$infile'";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
my $exc = '';
|
||||||
|
foreach my $glob (@Remove_Sources) {
|
||||||
|
# Fastcov does exact match not globbing at present
|
||||||
|
# Lcov requires whole path match so needs the glob
|
||||||
|
$glob =~ s!^\*!! if $Opt_Fastcov;
|
||||||
|
$glob =~ s!\*$!! if $Opt_Fastcov;
|
||||||
|
$exc .= " '$glob'";
|
||||||
|
}
|
||||||
|
if ($Opt_Fastcov) {
|
||||||
|
$inc = "--include ".$inc if $inc ne '';
|
||||||
|
$exc = "--exclude ".$exc if $exc ne '';
|
||||||
|
run("cd $cc_dir ; ${RealBin}/fastcov.py -C app_total.info ${inc} ${exc} -x --lcov -o app_total_f.info");
|
||||||
|
} else {
|
||||||
|
run("cd $cc_dir ; lcov --remove app_total.info $exc -o app_total_f.info");
|
||||||
|
}
|
||||||
|
travis_fold_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Opt_Stages{17}) {
|
||||||
|
travis_fold_start("report");
|
||||||
|
print "Stage 17: Create HTML\n";
|
||||||
|
run("cd $cc_dir ; genhtml app_total_f.info --demangle-cpp"
|
||||||
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
|
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
|
||||||
|
travis_fold_end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($Opt_Stage <= 9) {
|
if ($Opt_Stages{18}) {
|
||||||
|
travis_fold_start("upload");
|
||||||
|
print "Stage 18: Upload\n";
|
||||||
|
my $cmd = "bash <(curl -s https://codecov.io/bash) -f $cc_dir/app_total.info";
|
||||||
|
print "print: Not running: export CODECOV_TOKEN=<hidden>\n";
|
||||||
|
print "print: Not running: $cmd\n";
|
||||||
|
travis_fold_end();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($Opt_Stages{19}) {
|
||||||
print "*-* All Finished *-*\n";
|
print "*-* All Finished *-*\n";
|
||||||
|
print "\n";
|
||||||
|
print "* See report in ${cc_dir}/html/index.html\n";
|
||||||
|
print "* Remember to make distclean && ./configure before working on non-coverage\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sub clone_sources {
|
sub clone_sources {
|
||||||
my $cc_dir = shift;
|
my $cc_dir = shift;
|
||||||
my $excluded_lines = 0;
|
my $excluded_lines = 0;
|
||||||
|
my $excluded_br_lines = 0;
|
||||||
foreach my $glob (@Source_Globs) {
|
foreach my $glob (@Source_Globs) {
|
||||||
foreach my $infile (glob $glob) {
|
foreach my $infile (glob $glob) {
|
||||||
$infile !~ m!^/!
|
$infile !~ m!^/!
|
||||||
@@ -145,21 +327,35 @@ sub clone_sources {
|
|||||||
while (defined(my $line = $fh->getline)) {
|
while (defined(my $line = $fh->getline)) {
|
||||||
$lineno++;
|
$lineno++;
|
||||||
chomp $line;
|
chomp $line;
|
||||||
if ($line !~ m!// LCOV_EXCL_LINE!
|
if ($line =~ /LCOV_EXCL_LINE/) {
|
||||||
&& $line =~ /$Exclude_Line_Regexp/) {
|
$line .= " LCOV_EXCL_BR_LINE";
|
||||||
$line .= " //code_coverage: // LCOV_EXCL_LINE";
|
}
|
||||||
|
elsif ($line =~ /LCOV_EXCL_START/) {
|
||||||
|
$line .= " LCOV_EXCL_BR_START";
|
||||||
|
}
|
||||||
|
elsif ($line =~ /LCOV_EXCL_STOP/) {
|
||||||
|
$line .= " LCOV_EXCL_BR_STOP";
|
||||||
|
}
|
||||||
|
elsif ($line =~ /$Exclude_Line_Regexp/) {
|
||||||
|
$line .= " //code_coverage: // LCOV_EXCL_LINE LCOV_EXCL_BR_LINE";
|
||||||
$excluded_lines++;
|
$excluded_lines++;
|
||||||
|
$excluded_br_lines++;
|
||||||
|
#print "$infile:$lineno: $line";
|
||||||
|
}
|
||||||
|
elsif ($line =~ /$Exclude_Branch_Regexp/) {
|
||||||
|
$line .= " //code_coverage: // LCOV_EXCL_BR_LINE";
|
||||||
|
$excluded_br_lines++;
|
||||||
#print "$infile:$lineno: $line";
|
#print "$infile:$lineno: $line";
|
||||||
} else {
|
|
||||||
}
|
}
|
||||||
$ofh->print("$line\n");
|
$ofh->print("$line\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print "Source code lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
|
print "Number of source lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
|
||||||
|
print "Number of source lines automatically LCOV_EXCL_BR_LINE'ed: $excluded_br_lines\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
sub cleanup_abs_paths {
|
sub cleanup_abs_paths_info {
|
||||||
my $cc_dir = shift;
|
my $cc_dir = shift;
|
||||||
my $infile = shift;
|
my $infile = shift;
|
||||||
my $outfile = shift;
|
my $outfile = shift;
|
||||||
@@ -178,18 +374,41 @@ sub cleanup_abs_paths {
|
|||||||
$ofh->print(@lines);
|
$ofh->print(@lines);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub cleanup_abs_paths_json {
|
||||||
|
my $cc_dir = shift;
|
||||||
|
my $infile = shift;
|
||||||
|
my $outfile = shift;
|
||||||
|
# Handcrafted cleanup, alternative would be to deserialize/serialize JSON
|
||||||
|
# But JSON::Parse not installed by default
|
||||||
|
# JSON::PP more likely to be installed, but slower
|
||||||
|
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
|
||||||
|
my @lines;
|
||||||
|
while (defined(my $line = $fh->getline)) {
|
||||||
|
$line =~ s!"$ENV{VERILATOR_ROOT}/!"!g;
|
||||||
|
$line =~ s!"$cc_dir/!"!g;
|
||||||
|
$line =~ s!obj_dbg/verilog.y$!verilog.y!g;
|
||||||
|
push @lines, $line;
|
||||||
|
}
|
||||||
|
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
|
||||||
|
$ofh->print(@lines);
|
||||||
|
}
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
# .dat file callbacks
|
# .dat file callbacks
|
||||||
|
|
||||||
|
sub exclude_branch_regexp {
|
||||||
|
$Exclude_Branch_Regexp = shift;
|
||||||
|
}
|
||||||
sub exclude_line_regexp {
|
sub exclude_line_regexp {
|
||||||
$Exclude_Line_Regexp = shift;
|
$Exclude_Line_Regexp = shift;
|
||||||
}
|
}
|
||||||
|
sub remove_gcda_regexp {
|
||||||
|
$Remove_Gcda_Regexp = shift;
|
||||||
|
}
|
||||||
sub remove_source {
|
sub remove_source {
|
||||||
my @srcs = @_;
|
my @srcs = @_;
|
||||||
push @Remove_Sources, @srcs;
|
push @Remove_Sources, @srcs;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub source_globs {
|
sub source_globs {
|
||||||
my @dirs = @_;
|
my @dirs = @_;
|
||||||
push @Source_Globs, @dirs;
|
push @Source_Globs, @dirs;
|
||||||
@@ -206,6 +425,15 @@ sub run {
|
|||||||
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
|
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
our $_Travis_Action;
|
||||||
|
sub travis_fold_start {
|
||||||
|
$_Travis_Action = shift;
|
||||||
|
print "travis_fold:start:$_Travis_Action\n";
|
||||||
|
}
|
||||||
|
sub travis_fold_end {
|
||||||
|
print "travis_fold:end:$_Travis_Action\n";
|
||||||
|
}
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
@@ -231,13 +459,30 @@ This will rebuild the current object files.
|
|||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
|
=item --hashset I<hashset>
|
||||||
|
|
||||||
|
Pass test hashset onto driver.pl test harness.
|
||||||
|
|
||||||
=item --help
|
=item --help
|
||||||
|
|
||||||
Displays this message and program version and exits.
|
Displays this message and program version and exits.
|
||||||
|
|
||||||
=item -stage I<stage>
|
=item --scenarios I<scenarios>
|
||||||
|
|
||||||
Runs a specific stage (see the script).
|
Pass test scenarios onto driver.pl test harness.
|
||||||
|
|
||||||
|
=item --stages I<stage>
|
||||||
|
|
||||||
|
Runs a specific stage or range of stages (see the script).
|
||||||
|
|
||||||
|
=item --no-stop
|
||||||
|
|
||||||
|
Do not stop collecting data if tests fail.
|
||||||
|
|
||||||
|
=item --test I<test_regress_test_name>
|
||||||
|
|
||||||
|
Instead of normal regressions, run the specified test. May be specified
|
||||||
|
multiple times for multiple tests.
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,8 @@ source_globs("src/*.cpp",
|
|||||||
"include/*/*.c",
|
"include/*/*.c",
|
||||||
);
|
);
|
||||||
|
|
||||||
remove_source("/usr/include/*");
|
# Note *'s are removed when using fastcov
|
||||||
|
remove_source("/usr/*");
|
||||||
remove_source("*/include/sysc/*");
|
remove_source("*/include/sysc/*");
|
||||||
remove_source("*/V3ClkGater.cpp");
|
remove_source("*/V3ClkGater.cpp");
|
||||||
remove_source("*/V3ClkGater.h");
|
remove_source("*/V3ClkGater.h");
|
||||||
@@ -37,7 +38,21 @@ remove_source("*include/gtkwave/*");
|
|||||||
remove_source("*test_regress/*");
|
remove_source("*test_regress/*");
|
||||||
remove_source("*examples/*");
|
remove_source("*examples/*");
|
||||||
|
|
||||||
|
# Remove collected coverage on each little test main file
|
||||||
|
# Would just be removed with remove_source in later step
|
||||||
|
remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
|
||||||
|
|
||||||
exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b)/);
|
# Exclude line entirely, also excludes from function and branch coverage
|
||||||
|
exclude_line_regexp(qr/(\bv3fatalSrc\b
|
||||||
|
|\bfatalSrc\b
|
||||||
|
|\bVL_UNCOVERABLE\b
|
||||||
|
|\bVL_FATAL
|
||||||
|
|\bUASSERT
|
||||||
|
|\bERROR_RSVD_WORD
|
||||||
|
|\bV3ERROR_NA
|
||||||
|
|\bUINFO\b)/x);
|
||||||
|
|
||||||
|
# Exclude for branch coverage only
|
||||||
|
exclude_branch_regexp(qr/(\bdebug\(\))/x);
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
Executable
+744
@@ -0,0 +1,744 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
# Copyright 2018-present, Bryan Gillespie
|
||||||
|
"""
|
||||||
|
Author: Bryan Gillespie
|
||||||
|
https://github.com/RPGillespie6/fastcov
|
||||||
|
|
||||||
|
A massively parallel gcov wrapper for generating intermediate coverage formats fast
|
||||||
|
|
||||||
|
The goal of fastcov is to generate code coverage intermediate formats as fast as possible,
|
||||||
|
even for large projects with hundreds of gcda objects. The intermediate formats may then be
|
||||||
|
consumed by a report generator such as lcov's genhtml, or a dedicated frontend such as coveralls.
|
||||||
|
|
||||||
|
Sample Usage:
|
||||||
|
$ cd build_dir
|
||||||
|
$ ./fastcov.py --zerocounters
|
||||||
|
$ <run unit tests>
|
||||||
|
$ ./fastcov.py --exclude /usr/include test/ --lcov -o report.info
|
||||||
|
$ genhtml -o code_coverage report.info
|
||||||
|
"""
|
||||||
|
|
||||||
|
import re
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import glob
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import argparse
|
||||||
|
import threading
|
||||||
|
import subprocess
|
||||||
|
import multiprocessing
|
||||||
|
|
||||||
|
FASTCOV_VERSION = (1,7)
|
||||||
|
MINIMUM_PYTHON = (3,5)
|
||||||
|
MINIMUM_GCOV = (9,0,0)
|
||||||
|
|
||||||
|
# Interesting metrics
|
||||||
|
START_TIME = time.monotonic()
|
||||||
|
GCOVS_TOTAL = 0
|
||||||
|
GCOVS_SKIPPED = 0
|
||||||
|
|
||||||
|
# For when things go wrong...
|
||||||
|
# Start error codes at 3 because 1-2 are special
|
||||||
|
# See https://stackoverflow.com/a/1535733/2516916
|
||||||
|
EXIT_CODE = 0
|
||||||
|
EXIT_CODES = {
|
||||||
|
"gcov_version": 3,
|
||||||
|
"python_version": 4,
|
||||||
|
"unsupported_coverage_format": 5,
|
||||||
|
"excl_not_found": 6,
|
||||||
|
}
|
||||||
|
|
||||||
|
# Disable all logging in case developers are using this as a module
|
||||||
|
logging.disable(level=logging.CRITICAL)
|
||||||
|
|
||||||
|
class FastcovFormatter(logging.Formatter):
|
||||||
|
def format(self, record):
|
||||||
|
record.levelname = record.levelname.lower()
|
||||||
|
log_message = super(FastcovFormatter, self).format(record)
|
||||||
|
return "[{:.3f}s] {}".format(stopwatch(), log_message)
|
||||||
|
|
||||||
|
def chunks(l, n):
|
||||||
|
"""Yield successive n-sized chunks from l."""
|
||||||
|
for i in range(0, len(l), n):
|
||||||
|
yield l[i:i + n]
|
||||||
|
|
||||||
|
def setExitCode(key):
|
||||||
|
global EXIT_CODE
|
||||||
|
EXIT_CODE = EXIT_CODES[key]
|
||||||
|
|
||||||
|
def incrementCounters(total, skipped):
|
||||||
|
global GCOVS_TOTAL
|
||||||
|
global GCOVS_SKIPPED
|
||||||
|
GCOVS_TOTAL += total
|
||||||
|
GCOVS_SKIPPED += skipped
|
||||||
|
|
||||||
|
def stopwatch():
|
||||||
|
"""Return number of seconds since last time this was called."""
|
||||||
|
global START_TIME
|
||||||
|
end_time = time.monotonic()
|
||||||
|
delta = end_time - START_TIME
|
||||||
|
START_TIME = end_time
|
||||||
|
return delta
|
||||||
|
|
||||||
|
def parseVersionFromLine(version_str):
|
||||||
|
"""Given a string containing a dotted integer version, parse out integers and return as tuple."""
|
||||||
|
version = re.search(r'(\d+\.\d+\.\d+)', version_str)
|
||||||
|
|
||||||
|
if not version:
|
||||||
|
return (0,0,0)
|
||||||
|
|
||||||
|
return tuple(map(int, version.group(1).split(".")))
|
||||||
|
|
||||||
|
def getGcovVersion(gcov):
|
||||||
|
p = subprocess.Popen([gcov, "-v"], stdout=subprocess.PIPE)
|
||||||
|
output = p.communicate()[0].decode('UTF-8')
|
||||||
|
p.wait()
|
||||||
|
return parseVersionFromLine(output.split("\n")[0])
|
||||||
|
|
||||||
|
def removeFiles(files):
|
||||||
|
for file in files:
|
||||||
|
os.remove(file)
|
||||||
|
|
||||||
|
def getFilteredCoverageFiles(coverage_files, exclude):
|
||||||
|
def excludeGcda(gcda):
|
||||||
|
for ex in exclude:
|
||||||
|
if ex in gcda:
|
||||||
|
logging.debug("Omitting %s due to '--exclude-gcda %s'", gcda, ex)
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
return list(filter(excludeGcda, coverage_files))
|
||||||
|
|
||||||
|
def findCoverageFiles(cwd, coverage_files, use_gcno):
|
||||||
|
coverage_type = "user provided"
|
||||||
|
if not coverage_files:
|
||||||
|
coverage_type = "gcno" if use_gcno else "gcda"
|
||||||
|
coverage_files = glob.glob(os.path.join(os.path.abspath(cwd), "**/*." + coverage_type), recursive=True)
|
||||||
|
|
||||||
|
logging.info("Found {} coverage files ({})".format(len(coverage_files), coverage_type))
|
||||||
|
logging.debug("Coverage files found:\n %s", "\n ".join(coverage_files))
|
||||||
|
return coverage_files
|
||||||
|
|
||||||
|
def gcovWorker(data_q, metrics_q, args, chunk, gcov_filter_options):
|
||||||
|
base_report = {"sources": {}}
|
||||||
|
gcovs_total = 0
|
||||||
|
gcovs_skipped = 0
|
||||||
|
|
||||||
|
gcov_args = "-it"
|
||||||
|
if args.branchcoverage or args.xbranchcoverage:
|
||||||
|
gcov_args += "b"
|
||||||
|
|
||||||
|
p = subprocess.Popen([args.gcov, gcov_args] + chunk, cwd=args.cdirectory, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||||
|
for line in iter(p.stdout.readline, b''):
|
||||||
|
intermediate_json = json.loads(line.decode(sys.stdout.encoding))
|
||||||
|
intermediate_json_files = processGcovs(args.cdirectory, intermediate_json["files"], gcov_filter_options)
|
||||||
|
for f in intermediate_json_files:
|
||||||
|
distillSource(f, base_report["sources"], args.test_name, args.xbranchcoverage)
|
||||||
|
gcovs_total += len(intermediate_json["files"])
|
||||||
|
gcovs_skipped += len(intermediate_json["files"]) - len(intermediate_json_files)
|
||||||
|
|
||||||
|
p.wait()
|
||||||
|
data_q.put(base_report)
|
||||||
|
metrics_q.put((gcovs_total, gcovs_skipped))
|
||||||
|
|
||||||
|
def processGcdas(args, coverage_files, gcov_filter_options):
|
||||||
|
chunk_size = max(args.minimum_chunk, int(len(coverage_files) / args.jobs) + 1)
|
||||||
|
|
||||||
|
processes = []
|
||||||
|
data_q = multiprocessing.Queue()
|
||||||
|
metrics_q = multiprocessing.Queue()
|
||||||
|
for chunk in chunks(coverage_files, chunk_size):
|
||||||
|
p = multiprocessing.Process(target=gcovWorker, args=(data_q, metrics_q, args, chunk, gcov_filter_options))
|
||||||
|
processes.append(p)
|
||||||
|
p.start()
|
||||||
|
|
||||||
|
logging.info("Spawned {} gcov processes, each processing at most {} coverage files".format(len(processes), chunk_size))
|
||||||
|
|
||||||
|
fastcov_jsons = []
|
||||||
|
for p in processes:
|
||||||
|
fastcov_jsons.append(data_q.get())
|
||||||
|
incrementCounters(*metrics_q.get())
|
||||||
|
|
||||||
|
for p in processes:
|
||||||
|
p.join()
|
||||||
|
|
||||||
|
base_fastcov = fastcov_jsons.pop()
|
||||||
|
for fj in fastcov_jsons:
|
||||||
|
combineReports(base_fastcov, fj)
|
||||||
|
|
||||||
|
return base_fastcov
|
||||||
|
|
||||||
|
def shouldFilterSource(source, gcov_filter_options):
|
||||||
|
"""Returns true if the provided source file should be filtered due to CLI options, otherwise returns false."""
|
||||||
|
# If explicit sources were passed, check for match
|
||||||
|
if gcov_filter_options["sources"]:
|
||||||
|
if source not in gcov_filter_options["sources"]:
|
||||||
|
logging.debug("Filtering coverage for '%s' due to option '--source-files'", source)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Check exclude filter
|
||||||
|
for ex in gcov_filter_options["exclude"]:
|
||||||
|
if ex in source:
|
||||||
|
logging.debug("Filtering coverage for '%s' due to option '--exclude %s'", source, ex)
|
||||||
|
return True
|
||||||
|
|
||||||
|
# Check include filter
|
||||||
|
if gcov_filter_options["include"]:
|
||||||
|
included = False
|
||||||
|
for inc in gcov_filter_options["include"]:
|
||||||
|
if inc in source:
|
||||||
|
included = True
|
||||||
|
break
|
||||||
|
|
||||||
|
if not included:
|
||||||
|
logging.debug("Filtering coverage for '%s' due to option '--include %s'", source, " ".join(gcov_filter_options["include"]))
|
||||||
|
return True
|
||||||
|
|
||||||
|
return False
|
||||||
|
|
||||||
|
def filterFastcov(fastcov_json, args):
|
||||||
|
logging.info("Performing filtering operations (if applicable)")
|
||||||
|
gcov_filter_options = getGcovFilterOptions(args)
|
||||||
|
for source in list(fastcov_json["sources"].keys()):
|
||||||
|
if shouldFilterSource(source, gcov_filter_options):
|
||||||
|
del fastcov_json["sources"][source]
|
||||||
|
|
||||||
|
def processGcov(cwd, gcov, files, gcov_filter_options):
|
||||||
|
# Add absolute path
|
||||||
|
gcov["file_abs"] = os.path.abspath(os.path.join(cwd, gcov["file"]))
|
||||||
|
|
||||||
|
if shouldFilterSource(gcov["file_abs"], gcov_filter_options):
|
||||||
|
return
|
||||||
|
|
||||||
|
files.append(gcov)
|
||||||
|
logging.debug("Accepted coverage for '%s'", gcov["file_abs"])
|
||||||
|
|
||||||
|
def processGcovs(cwd, gcov_files, gcov_filter_options):
|
||||||
|
files = []
|
||||||
|
for gcov in gcov_files:
|
||||||
|
processGcov(cwd, gcov, files, gcov_filter_options)
|
||||||
|
return files
|
||||||
|
|
||||||
|
def dumpBranchCoverageToLcovInfo(f, branches):
|
||||||
|
branch_miss = 0
|
||||||
|
branch_found = 0
|
||||||
|
brda = []
|
||||||
|
for line_num, branch_counts in branches.items():
|
||||||
|
for i, count in enumerate(branch_counts):
|
||||||
|
# Branch (<line number>, <block number>, <branch number>, <taken>)
|
||||||
|
brda.append((line_num, int(i/2), i, count))
|
||||||
|
branch_miss += int(count == 0)
|
||||||
|
branch_found += 1
|
||||||
|
for v in sorted(brda):
|
||||||
|
f.write("BRDA:{},{},{},{}\n".format(*v))
|
||||||
|
f.write("BRF:{}\n".format(branch_found)) # Branches Found
|
||||||
|
f.write("BRH:{}\n".format(branch_found - branch_miss)) # Branches Hit
|
||||||
|
|
||||||
|
def dumpToLcovInfo(fastcov_json, output):
|
||||||
|
with open(output, "w") as f:
|
||||||
|
sources = fastcov_json["sources"]
|
||||||
|
for sf in sorted(sources.keys()):
|
||||||
|
for tn in sorted(sources[sf].keys()):
|
||||||
|
data = sources[sf][tn]
|
||||||
|
f.write("TN:{}\n".format(tn)) #Test Name - used mainly in conjuction with genhtml --show-details
|
||||||
|
f.write("SF:{}\n".format(sf)) #Source File
|
||||||
|
|
||||||
|
fn_miss = 0
|
||||||
|
fn = []
|
||||||
|
fnda = []
|
||||||
|
for function, fdata in data["functions"].items():
|
||||||
|
fn.append((fdata["start_line"], function)) # Function Start Line
|
||||||
|
fnda.append((fdata["execution_count"], function)) # Function Hits
|
||||||
|
fn_miss += int(fdata["execution_count"] == 0)
|
||||||
|
# NOTE: lcov sorts FN, but not FNDA.
|
||||||
|
for v in sorted(fn):
|
||||||
|
f.write("FN:{},{}\n".format(*v))
|
||||||
|
for v in sorted(fnda):
|
||||||
|
f.write("FNDA:{},{}\n".format(*v))
|
||||||
|
f.write("FNF:{}\n".format(len(data["functions"]))) #Functions Found
|
||||||
|
f.write("FNH:{}\n".format((len(data["functions"]) - fn_miss))) #Functions Hit
|
||||||
|
|
||||||
|
if data["branches"]:
|
||||||
|
dumpBranchCoverageToLcovInfo(f, data["branches"])
|
||||||
|
|
||||||
|
line_miss = 0
|
||||||
|
da = []
|
||||||
|
for line_num, count in data["lines"].items():
|
||||||
|
da.append((line_num, count))
|
||||||
|
line_miss += int(count == 0)
|
||||||
|
for v in sorted(da):
|
||||||
|
f.write("DA:{},{}\n".format(*v)) # Line
|
||||||
|
f.write("LF:{}\n".format(len(data["lines"]))) #Lines Found
|
||||||
|
f.write("LH:{}\n".format((len(data["lines"]) - line_miss))) #Lines Hit
|
||||||
|
f.write("end_of_record\n")
|
||||||
|
|
||||||
|
def getSourceLines(source, fallback_encodings=[]):
|
||||||
|
"""Return a list of lines from the provided source, trying to decode with fallback encodings if the default fails."""
|
||||||
|
default_encoding = sys.getdefaultencoding()
|
||||||
|
for encoding in [default_encoding] + fallback_encodings:
|
||||||
|
try:
|
||||||
|
with open(source, encoding=encoding) as f:
|
||||||
|
return f.readlines()
|
||||||
|
except UnicodeDecodeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
logging.warning("Could not decode '{}' with {} or fallback encodings ({}); ignoring errors".format(source, default_encoding, ",".join(fallback_encodings)))
|
||||||
|
with open(source, errors="ignore") as f:
|
||||||
|
return f.readlines()
|
||||||
|
|
||||||
|
def exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings):
|
||||||
|
start_line = 0
|
||||||
|
end_line = 0
|
||||||
|
# Start enumeration at line 1 because the first line of the file is line 1 not 0
|
||||||
|
for i, line in enumerate(getSourceLines(source, fallback_encodings), 1):
|
||||||
|
# Cycle through test names (likely only 1)
|
||||||
|
for test_name in fastcov_sources[source]:
|
||||||
|
fastcov_data = fastcov_sources[source][test_name]
|
||||||
|
|
||||||
|
# Build line to function dict so can quickly delete by line number
|
||||||
|
line_to_func = {}
|
||||||
|
for f in fastcov_data["functions"].keys():
|
||||||
|
l = fastcov_data["functions"][f]["start_line"]
|
||||||
|
if l not in line_to_func:
|
||||||
|
line_to_func[l] = set()
|
||||||
|
line_to_func[l].add(f)
|
||||||
|
|
||||||
|
if i in fastcov_data["branches"]:
|
||||||
|
del_exclude_br = exclude_branches_sw and any(line.lstrip().startswith(e) for e in exclude_branches_sw)
|
||||||
|
del_include_br = include_branches_sw and all(not line.lstrip().startswith(e) for e in include_branches_sw)
|
||||||
|
if del_exclude_br or del_include_br:
|
||||||
|
del fastcov_data["branches"][i]
|
||||||
|
|
||||||
|
if "LCOV_EXCL" not in line:
|
||||||
|
continue
|
||||||
|
|
||||||
|
if "LCOV_EXCL_LINE" in line:
|
||||||
|
for key in ["lines", "branches"]:
|
||||||
|
if i in fastcov_data[key]:
|
||||||
|
del fastcov_data[key][i]
|
||||||
|
if i in line_to_func:
|
||||||
|
for key in line_to_func[i]:
|
||||||
|
if key in fastcov_data["functions"]:
|
||||||
|
del fastcov_data["functions"][key]
|
||||||
|
elif "LCOV_EXCL_START" in line:
|
||||||
|
start_line = i
|
||||||
|
elif "LCOV_EXCL_STOP" in line:
|
||||||
|
end_line = i
|
||||||
|
|
||||||
|
if not start_line:
|
||||||
|
end_line = 0
|
||||||
|
continue
|
||||||
|
|
||||||
|
for key in ["lines", "branches"]:
|
||||||
|
for line_num in list(fastcov_data[key].keys()):
|
||||||
|
if start_line <= line_num <= end_line:
|
||||||
|
del fastcov_data[key][line_num]
|
||||||
|
|
||||||
|
for line_num in range(start_line, end_line):
|
||||||
|
if line_num in line_to_func:
|
||||||
|
for key in line_to_func[line_num]:
|
||||||
|
if key in fastcov_data["functions"]:
|
||||||
|
del fastcov_data["functions"][key]
|
||||||
|
|
||||||
|
start_line = end_line = 0
|
||||||
|
elif "LCOV_EXCL_BR_LINE" in line:
|
||||||
|
if i in fastcov_data["branches"]:
|
||||||
|
del fastcov_data["branches"][i]
|
||||||
|
|
||||||
|
def exclMarkerWorker(fastcov_sources, chunk, exclude_branches_sw, include_branches_sw, fallback_encodings):
|
||||||
|
for source in chunk:
|
||||||
|
try:
|
||||||
|
exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings)
|
||||||
|
except FileNotFoundError:
|
||||||
|
logging.error("Could not find '%s' to scan for exclusion markers...", source)
|
||||||
|
setExitCode("excl_not_found") # Set exit code because of error
|
||||||
|
|
||||||
|
def scanExclusionMarkers(fastcov_json, jobs, exclude_branches_sw, include_branches_sw, min_chunk_size, fallback_encodings):
|
||||||
|
chunk_size = max(min_chunk_size, int(len(fastcov_json["sources"]) / jobs) + 1)
|
||||||
|
|
||||||
|
threads = []
|
||||||
|
for chunk in chunks(list(fastcov_json["sources"].keys()), chunk_size):
|
||||||
|
t = threading.Thread(target=exclMarkerWorker, args=(fastcov_json["sources"], chunk, exclude_branches_sw, include_branches_sw, fallback_encodings))
|
||||||
|
threads.append(t)
|
||||||
|
t.start()
|
||||||
|
|
||||||
|
logging.info("Spawned {} threads each scanning at most {} source files".format(len(threads), chunk_size))
|
||||||
|
for t in threads:
|
||||||
|
t.join()
|
||||||
|
|
||||||
|
def distillFunction(function_raw, functions):
|
||||||
|
function_name = function_raw["name"]
|
||||||
|
# NOTE: need to explicitly cast all counts coming from gcov to int - this is because gcov's json library
|
||||||
|
# will pass as scientific notation (i.e. 12+e45)
|
||||||
|
start_line = int(function_raw["start_line"])
|
||||||
|
execution_count = int(function_raw["execution_count"])
|
||||||
|
if function_name not in functions:
|
||||||
|
functions[function_name] = {
|
||||||
|
"start_line": start_line,
|
||||||
|
"execution_count": execution_count
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
functions[function_name]["execution_count"] += execution_count
|
||||||
|
|
||||||
|
def emptyBranchSet(branch1, branch2):
|
||||||
|
return (branch1["count"] == 0 and branch2["count"] == 0)
|
||||||
|
|
||||||
|
def matchingBranchSet(branch1, branch2):
|
||||||
|
return (branch1["count"] == branch2["count"])
|
||||||
|
|
||||||
|
def filterExceptionalBranches(branches):
|
||||||
|
filtered_branches = []
|
||||||
|
exception_branch = False
|
||||||
|
for i in range(0, len(branches), 2):
|
||||||
|
if i+1 >= len(branches):
|
||||||
|
filtered_branches.append(branches[i])
|
||||||
|
break
|
||||||
|
|
||||||
|
# Filter exceptional branch noise
|
||||||
|
if branches[i+1]["throw"]:
|
||||||
|
exception_branch = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Filter initializer list noise
|
||||||
|
if exception_branch and emptyBranchSet(branches[i], branches[i+1]) and len(filtered_branches) >= 2 and matchingBranchSet(filtered_branches[-1], filtered_branches[-2]):
|
||||||
|
return []
|
||||||
|
|
||||||
|
filtered_branches.append(branches[i])
|
||||||
|
filtered_branches.append(branches[i+1])
|
||||||
|
|
||||||
|
return filtered_branches
|
||||||
|
|
||||||
|
def distillLine(line_raw, lines, branches, include_exceptional_branches):
|
||||||
|
line_number = int(line_raw["line_number"])
|
||||||
|
count = int(line_raw["count"])
|
||||||
|
if line_number not in lines:
|
||||||
|
lines[line_number] = count
|
||||||
|
else:
|
||||||
|
lines[line_number] += count
|
||||||
|
|
||||||
|
# Filter out exceptional branches by default unless requested otherwise
|
||||||
|
if not include_exceptional_branches:
|
||||||
|
line_raw["branches"] = filterExceptionalBranches(line_raw["branches"])
|
||||||
|
|
||||||
|
# Increment all branch counts
|
||||||
|
for i, branch in enumerate(line_raw["branches"]):
|
||||||
|
if line_number not in branches:
|
||||||
|
branches[line_number] = []
|
||||||
|
blen = len(branches[line_number])
|
||||||
|
glen = len(line_raw["branches"])
|
||||||
|
if blen < glen:
|
||||||
|
branches[line_number] += [0] * (glen - blen)
|
||||||
|
branches[line_number][i] += int(branch["count"])
|
||||||
|
|
||||||
|
def distillSource(source_raw, sources, test_name, include_exceptional_branches):
|
||||||
|
source_name = source_raw["file_abs"]
|
||||||
|
if source_name not in sources:
|
||||||
|
sources[source_name] = {
|
||||||
|
test_name: {
|
||||||
|
"functions": {},
|
||||||
|
"branches": {},
|
||||||
|
"lines": {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for function in source_raw["functions"]:
|
||||||
|
distillFunction(function, sources[source_name][test_name]["functions"])
|
||||||
|
|
||||||
|
for line in source_raw["lines"]:
|
||||||
|
distillLine(line, sources[source_name][test_name]["lines"], sources[source_name][test_name]["branches"], include_exceptional_branches)
|
||||||
|
|
||||||
|
def dumpToJson(intermediate, output):
|
||||||
|
with open(output, "w") as f:
|
||||||
|
json.dump(intermediate, f)
|
||||||
|
|
||||||
|
def getGcovFilterOptions(args):
|
||||||
|
return {
|
||||||
|
"sources": set([os.path.abspath(s) for s in args.sources]), #Make paths absolute, use set for fast lookups
|
||||||
|
"include": args.includepost,
|
||||||
|
"exclude": args.excludepost,
|
||||||
|
}
|
||||||
|
|
||||||
|
def addDicts(dict1, dict2):
|
||||||
|
"""Add dicts together by value. i.e. addDicts({"a":1,"b":0}, {"a":2}) == {"a":3,"b":0}."""
|
||||||
|
result = {k:v for k,v in dict1.items()}
|
||||||
|
for k,v in dict2.items():
|
||||||
|
if k in result:
|
||||||
|
result[k] += v
|
||||||
|
else:
|
||||||
|
result[k] = v
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
def addLists(list1, list2):
|
||||||
|
"""Add lists together by value. i.e. addLists([1,1], [2,2]) == [3,3]."""
|
||||||
|
# Find big list and small list
|
||||||
|
blist, slist = list(list2), list(list1)
|
||||||
|
if len(list1) > len(list2):
|
||||||
|
blist, slist = slist, blist
|
||||||
|
|
||||||
|
# Overlay small list onto big list
|
||||||
|
for i, b in enumerate(slist):
|
||||||
|
blist[i] += b
|
||||||
|
|
||||||
|
return blist
|
||||||
|
|
||||||
|
def combineReports(base, overlay):
|
||||||
|
for source, scov in overlay["sources"].items():
|
||||||
|
# Combine Source Coverage
|
||||||
|
if source not in base["sources"]:
|
||||||
|
base["sources"][source] = scov
|
||||||
|
continue
|
||||||
|
|
||||||
|
for test_name, tcov in scov.items():
|
||||||
|
# Combine Source Test Name Coverage
|
||||||
|
if test_name not in base["sources"][source]:
|
||||||
|
base["sources"][source][test_name] = tcov
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Drill down and create convenience variable
|
||||||
|
base_data = base["sources"][source][test_name]
|
||||||
|
|
||||||
|
# Combine Line Coverage
|
||||||
|
base_data["lines"] = addDicts(base_data["lines"], tcov["lines"])
|
||||||
|
|
||||||
|
# Combine Branch Coverage
|
||||||
|
for branch, cov in tcov["branches"].items():
|
||||||
|
if branch not in base_data["branches"]:
|
||||||
|
base_data["branches"][branch] = cov
|
||||||
|
else:
|
||||||
|
base_data["branches"][branch] = addLists(base_data["branches"][branch], cov)
|
||||||
|
|
||||||
|
# Combine Function Coverage
|
||||||
|
for function, cov in tcov["functions"].items():
|
||||||
|
if function not in base_data["functions"]:
|
||||||
|
base_data["functions"][function] = cov
|
||||||
|
else:
|
||||||
|
base_data["functions"][function]["execution_count"] += cov["execution_count"]
|
||||||
|
|
||||||
|
def parseInfo(path):
|
||||||
|
"""Parse an lcov .info file into fastcov json."""
|
||||||
|
fastcov_json = {
|
||||||
|
"sources": {}
|
||||||
|
}
|
||||||
|
|
||||||
|
with open(path) as f:
|
||||||
|
for line in f:
|
||||||
|
if line.startswith("TN:"):
|
||||||
|
current_test_name = line[3:].strip()
|
||||||
|
elif line.startswith("SF:"):
|
||||||
|
current_sf = line[3:].strip()
|
||||||
|
fastcov_json["sources"][current_sf] = {
|
||||||
|
current_test_name: {
|
||||||
|
"functions": {},
|
||||||
|
"branches": {},
|
||||||
|
"lines": {},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
current_data = fastcov_json["sources"][current_sf][current_test_name]
|
||||||
|
elif line.startswith("FN:"):
|
||||||
|
line_num, function_name = line[3:].strip().split(",")
|
||||||
|
current_data["functions"][function_name] = {}
|
||||||
|
current_data["functions"][function_name]["start_line"] = int(line_num)
|
||||||
|
elif line.startswith("FNDA:"):
|
||||||
|
count, function_name = line[5:].strip().split(",")
|
||||||
|
current_data["functions"][function_name]["execution_count"] = int(count)
|
||||||
|
elif line.startswith("DA:"):
|
||||||
|
line_num, count = line[3:].strip().split(",")
|
||||||
|
current_data["lines"][line_num] = int(count)
|
||||||
|
elif line.startswith("BRDA:"):
|
||||||
|
branch_tokens = line[5:].strip().split(",")
|
||||||
|
line_num, count = branch_tokens[0], branch_tokens[-1]
|
||||||
|
if line_num not in current_data["branches"]:
|
||||||
|
current_data["branches"][line_num] = []
|
||||||
|
current_data["branches"][line_num].append(int(count))
|
||||||
|
|
||||||
|
return fastcov_json
|
||||||
|
|
||||||
|
def convertKeysToInt(report):
|
||||||
|
for source in report["sources"].keys():
|
||||||
|
for test_name in report["sources"][source].keys():
|
||||||
|
report_data = report["sources"][source][test_name]
|
||||||
|
report_data["lines"] = {int(k):v for k,v in report_data["lines"].items()}
|
||||||
|
report_data["branches"] = {int(k):v for k,v in report_data["branches"].items()}
|
||||||
|
|
||||||
|
def parseAndCombine(paths):
|
||||||
|
base_report = {}
|
||||||
|
|
||||||
|
for path in paths:
|
||||||
|
if path.endswith(".json"):
|
||||||
|
with open(path) as f:
|
||||||
|
report = json.load(f)
|
||||||
|
elif path.endswith(".info"):
|
||||||
|
report = parseInfo(path)
|
||||||
|
else:
|
||||||
|
logging.error("Currently only fastcov .json and lcov .info supported for combine operations, aborting due to %s...\n", path)
|
||||||
|
sys.exit(EXIT_CODES["unsupported_coverage_format"])
|
||||||
|
|
||||||
|
# In order for sorting to work later when we serialize,
|
||||||
|
# make sure integer keys are int
|
||||||
|
convertKeysToInt(report)
|
||||||
|
|
||||||
|
if not base_report:
|
||||||
|
base_report = report
|
||||||
|
logging.info("Setting {} as base report".format(path))
|
||||||
|
else:
|
||||||
|
combineReports(base_report, report)
|
||||||
|
logging.info("Adding {} to base report".format(path))
|
||||||
|
|
||||||
|
return base_report
|
||||||
|
|
||||||
|
def getCombineCoverage(args):
|
||||||
|
logging.info("Performing combine operation")
|
||||||
|
fastcov_json = parseAndCombine(args.combine)
|
||||||
|
filterFastcov(fastcov_json, args)
|
||||||
|
return fastcov_json
|
||||||
|
|
||||||
|
def getGcovCoverage(args):
|
||||||
|
# Need at least python 3.5 because of use of recursive glob
|
||||||
|
checkPythonVersion(sys.version_info[0:2])
|
||||||
|
|
||||||
|
# Need at least gcov 9.0.0 because that's when gcov JSON and stdout streaming was introduced
|
||||||
|
checkGcovVersion(getGcovVersion(args.gcov))
|
||||||
|
|
||||||
|
# Get list of gcda files to process
|
||||||
|
coverage_files = findCoverageFiles(args.directory, args.coverage_files, args.use_gcno)
|
||||||
|
|
||||||
|
# If gcda/gcno filtering is enabled, filter them out now
|
||||||
|
if args.excludepre:
|
||||||
|
coverage_files = getFilteredCoverageFiles(coverage_files, args.excludepre)
|
||||||
|
logging.info("Found {} coverage files after filtering".format(len(coverage_files)))
|
||||||
|
|
||||||
|
# We "zero" the "counters" by simply deleting all gcda files
|
||||||
|
if args.zerocounters:
|
||||||
|
removeFiles(coverage_files)
|
||||||
|
logging.info("Removed {} .gcda files".format(len(coverage_files)))
|
||||||
|
sys.exit()
|
||||||
|
|
||||||
|
# Fire up one gcov per cpu and start processing gcdas
|
||||||
|
gcov_filter_options = getGcovFilterOptions(args)
|
||||||
|
fastcov_json = processGcdas(args, coverage_files, gcov_filter_options)
|
||||||
|
|
||||||
|
# Summarize processing results
|
||||||
|
logging.info("Processed {} .gcov files ({} total, {} skipped)".format(GCOVS_TOTAL - GCOVS_SKIPPED, GCOVS_TOTAL, GCOVS_SKIPPED))
|
||||||
|
logging.debug("Final report will contain coverage for the following %d source files:\n %s", len(fastcov_json["sources"]), "\n ".join(fastcov_json["sources"]))
|
||||||
|
|
||||||
|
return fastcov_json
|
||||||
|
|
||||||
|
def dumpFile(fastcov_json, args):
|
||||||
|
if args.lcov:
|
||||||
|
dumpToLcovInfo(fastcov_json, args.output)
|
||||||
|
logging.info("Created lcov info file '{}'".format(args.output))
|
||||||
|
else:
|
||||||
|
dumpToJson(fastcov_json, args.output)
|
||||||
|
logging.info("Created fastcov json file '{}'".format(args.output))
|
||||||
|
|
||||||
|
def tupleToDotted(tup):
|
||||||
|
return ".".join(map(str, tup))
|
||||||
|
|
||||||
|
def parseArgs():
|
||||||
|
parser = argparse.ArgumentParser(description='A parallel gcov wrapper for fast coverage report generation')
|
||||||
|
parser.add_argument('-z', '--zerocounters', dest='zerocounters', action="store_true", help='Recursively delete all gcda files')
|
||||||
|
|
||||||
|
# Enable Branch Coverage
|
||||||
|
parser.add_argument('-b', '--branch-coverage', dest='branchcoverage', action="store_true", help='Include only the most useful branches in the coverage report.')
|
||||||
|
parser.add_argument('-B', '--exceptional-branch-coverage', dest='xbranchcoverage', action="store_true", help='Include ALL branches in the coverage report (including potentially noisy exceptional branches).')
|
||||||
|
parser.add_argument('-A', '--exclude-br-lines-starting-with', dest='exclude_branches_sw', nargs="+", metavar='', default=[], help='Exclude branches from lines starting with one of the provided strings (i.e. assert, return, etc.)')
|
||||||
|
parser.add_argument('-a', '--include-br-lines-starting-with', dest='include_branches_sw', nargs="+", metavar='', default=[], help='Include only branches from lines starting with one of the provided strings (i.e. if, else, while, etc.)')
|
||||||
|
parser.add_argument('-X', '--skip-exclusion-markers', dest='skip_exclusion_markers', action="store_true", help='Skip reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
|
||||||
|
parser.add_argument('-x', '--scan-exclusion-markers', dest='scan_exclusion_markers', action="store_true", help='(Combine operations) Force reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
|
||||||
|
|
||||||
|
# Capture untested file coverage as well via gcno
|
||||||
|
parser.add_argument('-n', '--process-gcno', dest='use_gcno', action="store_true", help='Process both gcno and gcda coverage files. This option is useful for capturing untested files in the coverage report.')
|
||||||
|
|
||||||
|
# Filtering Options
|
||||||
|
parser.add_argument('-s', '--source-files', dest='sources', nargs="+", metavar='', default=[], help='Filter: Specify exactly which source files should be included in the final report. Paths must be either absolute or relative to current directory.')
|
||||||
|
parser.add_argument('-e', '--exclude', dest='excludepost', nargs="+", metavar='', default=[], help='Filter: Exclude source files from final report if they contain one of the provided substrings (i.e. /usr/include test/, etc.)')
|
||||||
|
parser.add_argument('-i', '--include', dest='includepost', nargs="+", metavar='', default=[], help='Filter: Only include source files in final report that contain one of the provided substrings (i.e. src/ etc.)')
|
||||||
|
parser.add_argument('-f', '--gcda-files', dest='coverage_files', nargs="+", metavar='', default=[], help='Filter: Specify exactly which gcda or gcno files should be processed. Note that specifying gcno causes both gcno and gcda to be processed.')
|
||||||
|
parser.add_argument('-E', '--exclude-gcda', dest='excludepre', nargs="+", metavar='', default=[], help='Filter: Exclude gcda or gcno files from being processed via simple find matching (not regex)')
|
||||||
|
|
||||||
|
parser.add_argument('-g', '--gcov', dest='gcov', default='gcov', help='Which gcov binary to use')
|
||||||
|
|
||||||
|
parser.add_argument('-d', '--search-directory', dest='directory', default=".", help='Base directory to recursively search for gcda files (default: .)')
|
||||||
|
parser.add_argument('-c', '--compiler-directory', dest='cdirectory', default=".", help='Base directory compiler was invoked from (default: .) \
|
||||||
|
This needs to be set if invoking fastcov from somewhere other than the base compiler directory.')
|
||||||
|
|
||||||
|
parser.add_argument('-j', '--jobs', dest='jobs', type=int, default=multiprocessing.cpu_count(), help='Number of parallel gcov to spawn (default: {}).'.format(multiprocessing.cpu_count()))
|
||||||
|
parser.add_argument('-m', '--minimum-chunk-size', dest='minimum_chunk', type=int, default=5, help='Minimum number of files a thread should process (default: 5). \
|
||||||
|
If you have only 4 gcda files but they are monstrously huge, you could change this value to a 1 so that each thread will only process 1 gcda. Otherwise fastcov will spawn only 1 thread to process all of them.')
|
||||||
|
|
||||||
|
parser.add_argument('-F', '--fallback-encodings', dest='fallback_encodings', nargs="+", metavar='', default=[], help='List of encodings to try if opening a source file with the default fails (i.e. latin1, etc.). This option is not usually needed.')
|
||||||
|
|
||||||
|
parser.add_argument('-l', '--lcov', dest='lcov', action="store_true", help='Output in lcov info format instead of fastcov json')
|
||||||
|
parser.add_argument('-o', '--output', dest='output', default="coverage.json", help='Name of output file (default: coverage.json)')
|
||||||
|
parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", help='Suppress output to stdout')
|
||||||
|
|
||||||
|
parser.add_argument('-t', '--test-name', dest='test_name', default="", help='Specify a test name for the coverage. Equivalent to lcov\'s `-t`.')
|
||||||
|
parser.add_argument('-C', '--add-tracefile', dest='combine', nargs="+", help='Combine multiple coverage files into one. If this flag is specified, fastcov will do a combine operation instead invoking gcov. Equivalent to lcov\'s `-a`.')
|
||||||
|
|
||||||
|
parser.add_argument('-V', '--verbose', dest="verbose", action="store_true", help="Print more detailed information about what fastcov is doing")
|
||||||
|
parser.add_argument('-v', '--version', action="version", version='%(prog)s {version}'.format(version=__version__), help="Show program's version number and exit")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
return args
|
||||||
|
|
||||||
|
def checkPythonVersion(version):
|
||||||
|
"""Exit if the provided python version is less than the supported version."""
|
||||||
|
if version < MINIMUM_PYTHON:
|
||||||
|
sys.stderr.write("Minimum python version {} required, found {}\n".format(tupleToDotted(MINIMUM_PYTHON), tupleToDotted(version)))
|
||||||
|
sys.exit(EXIT_CODES["python_version"])
|
||||||
|
|
||||||
|
def checkGcovVersion(version):
|
||||||
|
"""Exit if the provided gcov version is less than the supported version."""
|
||||||
|
if version < MINIMUM_GCOV:
|
||||||
|
sys.stderr.write("Minimum gcov version {} required, found {}\n".format(tupleToDotted(MINIMUM_GCOV), tupleToDotted(version)))
|
||||||
|
sys.exit(EXIT_CODES["gcov_version"])
|
||||||
|
|
||||||
|
def setupLogging(quiet, verbose):
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
handler.setFormatter(FastcovFormatter("[%(levelname)s]: %(message)s"))
|
||||||
|
|
||||||
|
root = logging.getLogger()
|
||||||
|
root.setLevel(logging.INFO)
|
||||||
|
root.addHandler(handler)
|
||||||
|
|
||||||
|
if not quiet:
|
||||||
|
logging.disable(level=logging.NOTSET) # Re-enable logging
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
root.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
def main():
|
||||||
|
args = parseArgs()
|
||||||
|
|
||||||
|
# Setup logging
|
||||||
|
setupLogging(args.quiet, args.verbose)
|
||||||
|
|
||||||
|
# Get report from appropriate source
|
||||||
|
if args.combine:
|
||||||
|
fastcov_json = getCombineCoverage(args)
|
||||||
|
skip_exclusion_markers = not args.scan_exclusion_markers
|
||||||
|
else:
|
||||||
|
fastcov_json = getGcovCoverage(args)
|
||||||
|
skip_exclusion_markers = args.skip_exclusion_markers
|
||||||
|
|
||||||
|
# Scan for exclusion markers
|
||||||
|
if not skip_exclusion_markers:
|
||||||
|
scanExclusionMarkers(fastcov_json, args.jobs, args.exclude_branches_sw, args.include_branches_sw, args.minimum_chunk, args.fallback_encodings)
|
||||||
|
logging.info("Scanned {} source files for exclusion markers".format(len(fastcov_json["sources"])))
|
||||||
|
|
||||||
|
# Dump to desired file format
|
||||||
|
dumpFile(fastcov_json, args)
|
||||||
|
|
||||||
|
# If there was an error along the way, but we still completed the pipeline...
|
||||||
|
if EXIT_CODE:
|
||||||
|
sys.exit(EXIT_CODE)
|
||||||
|
|
||||||
|
# Set package version... it's way down here so that we can call tupleToDotted
|
||||||
|
__version__ = tupleToDotted(FASTCOV_VERSION)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -1,257 +0,0 @@
|
|||||||
#!/usr/bin/env perl
|
|
||||||
# See copyright, etc in below POD section.
|
|
||||||
######################################################################
|
|
||||||
|
|
||||||
use warnings;
|
|
||||||
use Getopt::Long;
|
|
||||||
#use Data::Dumper; $Data::Dumper::Indent=1; $Data::Dumper::Sortkeys=1; #Debug
|
|
||||||
use IO::File;
|
|
||||||
use IO::Dir;
|
|
||||||
use Pod::Usage;
|
|
||||||
use strict;
|
|
||||||
use vars qw($Debug);
|
|
||||||
|
|
||||||
our $VERSION = '0.001';
|
|
||||||
our $Opt_Widen = 1;
|
|
||||||
|
|
||||||
#======================================================================
|
|
||||||
# main
|
|
||||||
|
|
||||||
autoflush STDOUT 1;
|
|
||||||
autoflush STDERR 1;
|
|
||||||
Getopt::Long::config("no_auto_abbrev");
|
|
||||||
if (! GetOptions (
|
|
||||||
"debug" => sub { $Debug = 1; },
|
|
||||||
"help" => sub { print "Version $VERSION\n";
|
|
||||||
pod2usage(-verbose=>2, -exitval => 0,
|
|
||||||
output=>\*STDOUT, -noperldoc=>1); },
|
|
||||||
"narrow!" => sub { $Opt_Widen = 0; },
|
|
||||||
"version" => sub { print "Version $VERSION\n"; exit(0); },
|
|
||||||
"widen!" => sub { $Opt_Widen = 1; }, # Default, undocumented
|
|
||||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
|
||||||
)) {
|
|
||||||
die "%Error: Bad usage, try 'git_untabify --help'\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
read_patch();
|
|
||||||
|
|
||||||
#######################################################################
|
|
||||||
|
|
||||||
sub read_patch {
|
|
||||||
my $filename = undef;
|
|
||||||
my $lineno = 0;
|
|
||||||
my $hunk = 0;
|
|
||||||
my $editlines = {};
|
|
||||||
while (defined(my $line = <STDIN>)) {
|
|
||||||
chomp $line;
|
|
||||||
if ($line =~ m!^\+\+\+ b/(.*)!) {
|
|
||||||
find_edits($editlines);
|
|
||||||
edit_file($filename, $editlines);
|
|
||||||
$filename = $1;
|
|
||||||
$lineno = 0;
|
|
||||||
$editlines = {};
|
|
||||||
print "FILE $filename\n" if $Debug;
|
|
||||||
}
|
|
||||||
elsif ($line =~ m!^@@ -?[0-9]+,?[0-9]* \+?([0-9]+)!) {
|
|
||||||
$lineno = $1 - 1;
|
|
||||||
++$hunk;
|
|
||||||
print " LINE $1 $line" if $Debug;
|
|
||||||
}
|
|
||||||
elsif ($line =~ m!^ !) {
|
|
||||||
++$lineno;
|
|
||||||
$editlines->{$lineno} = {line => $line,
|
|
||||||
hunk => $hunk,
|
|
||||||
user_edit => 0, };
|
|
||||||
}
|
|
||||||
elsif ($line =~ m!^\+!) {
|
|
||||||
++$lineno;
|
|
||||||
print " $lineno: $line" if $Debug;
|
|
||||||
$editlines->{$lineno} = {line => $line,
|
|
||||||
hunk => $hunk,
|
|
||||||
user_edit => 1, };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
find_edits($editlines);
|
|
||||||
edit_file($filename, $editlines);
|
|
||||||
}
|
|
||||||
|
|
||||||
sub find_edits {
|
|
||||||
my $editlines = shift;
|
|
||||||
# Expand edit regions so if have edited line, non-edited line, edited
|
|
||||||
# line, we will tab expand the middle ones.
|
|
||||||
my %hunk_firstlines;
|
|
||||||
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
|
|
||||||
my $hunk = $editlines->{$lineno}{hunk};
|
|
||||||
$hunk_firstlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
|
|
||||||
}
|
|
||||||
my %hunk_lastlines;
|
|
||||||
foreach my $lineno (sort {$b <=> $a} keys %$editlines) {
|
|
||||||
my $hunk = $editlines->{$lineno}{hunk};
|
|
||||||
$hunk_lastlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($Opt_Widen) {
|
|
||||||
# Expand to include }'s that finish basic block
|
|
||||||
foreach my $hunk (keys %hunk_lastlines) {
|
|
||||||
while (my $lineno = $hunk_lastlines{$hunk}) {
|
|
||||||
++$lineno;
|
|
||||||
if (($editlines->{$lineno}{line} || "")
|
|
||||||
=~ /^[+ ]\s+}[ \t};]*$/) {
|
|
||||||
$hunk_lastlines{$hunk} = $lineno;
|
|
||||||
} else {
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
# Expand to always untabify at least 3 lines (so that future diff will
|
|
||||||
# have non-tabs within a edit hunk distance
|
|
||||||
foreach my $hunk (keys %hunk_firstlines) {
|
|
||||||
if ($hunk_firstlines{$hunk} == $hunk_lastlines{$hunk}) {
|
|
||||||
--$hunk_firstlines{$hunk};
|
|
||||||
++$hunk_lastlines{$hunk};
|
|
||||||
}
|
|
||||||
elsif ($hunk_firstlines{$hunk}+1 == $hunk_lastlines{$hunk}) {
|
|
||||||
++$hunk_lastlines{$hunk};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
|
|
||||||
if (($editlines->{$lineno}{line}||"") =~ /\t/) {
|
|
||||||
my $hunk = $editlines->{$lineno}{hunk};
|
|
||||||
if ($hunk_firstlines{$hunk} <= $lineno && $hunk_lastlines{$hunk} >= $lineno) {
|
|
||||||
$editlines->{$lineno}{editit} = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sub edit_file {
|
|
||||||
my $filename = shift;
|
|
||||||
my $editlines = shift;
|
|
||||||
|
|
||||||
my @editits;
|
|
||||||
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
|
|
||||||
push @editits, $lineno if $editlines->{$lineno}{editit};
|
|
||||||
}
|
|
||||||
|
|
||||||
return if $#editits < 0;
|
|
||||||
if (ignore($filename)) {
|
|
||||||
print "%Warning: Ignoring $filename\n";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
print "Edit $filename ",join(",",@editits),"\n";
|
|
||||||
|
|
||||||
my $lineno = 0;
|
|
||||||
my @out;
|
|
||||||
{
|
|
||||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
|
|
||||||
while (defined(my $line = $fh->getline)) {
|
|
||||||
++$lineno;
|
|
||||||
if ($editlines->{$lineno}{editit}) {
|
|
||||||
print $line;
|
|
||||||
push @out, untabify($line);
|
|
||||||
} else {
|
|
||||||
push @out, $line;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$fh->close;
|
|
||||||
}
|
|
||||||
{
|
|
||||||
my $fh = IO::File->new(">${filename}.untab") or die "%Error: $! ${filename}.untab,";
|
|
||||||
$fh->print(join('',@out));
|
|
||||||
$fh->close;
|
|
||||||
|
|
||||||
my ($dev,$ino,$mode) = stat($filename);
|
|
||||||
chmod $mode, "${filename}.untab";
|
|
||||||
}
|
|
||||||
|
|
||||||
rename("${filename}.untab", $filename) or die "%Error: $! ${filename}.untab,";
|
|
||||||
}
|
|
||||||
|
|
||||||
sub ignore {
|
|
||||||
my $filename = shift;
|
|
||||||
return 1 if ($filename =~ /(Makefile|\.mk)/);
|
|
||||||
return 1 if ($filename =~ /\.(y|l|out|vcd)$/);
|
|
||||||
return 1 if ($filename =~ /gtkwave/);
|
|
||||||
#
|
|
||||||
return 0 if ($filename =~ /\.(sv|v|vh|svh|h|vc|cpp|pl)$/);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
sub untabify {
|
|
||||||
my $line = shift;
|
|
||||||
my $out = "";
|
|
||||||
my $col = 0;
|
|
||||||
foreach my $c (split //, $line) {
|
|
||||||
if ($c eq "\t") {
|
|
||||||
my $destcol = int(($col+8)/8)*8;
|
|
||||||
while ($col < $destcol) { ++$col; $out .= " "; }
|
|
||||||
} else {
|
|
||||||
$out .= $c;
|
|
||||||
$col++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return $out;
|
|
||||||
}
|
|
||||||
|
|
||||||
#######################################################################
|
|
||||||
__END__
|
|
||||||
|
|
||||||
=pod
|
|
||||||
|
|
||||||
=head1 NAME
|
|
||||||
|
|
||||||
git_untabify - Pipe a git diff report and untabify differences
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
|
||||||
|
|
||||||
git diff a..b | git_untabify
|
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
|
||||||
|
|
||||||
Take a patch file, and edit the files in the destination patch list to
|
|
||||||
untabify the related patch lines.
|
|
||||||
|
|
||||||
=head1 ARGUMENTS
|
|
||||||
|
|
||||||
=over 4
|
|
||||||
|
|
||||||
=item --help
|
|
||||||
|
|
||||||
Displays this message and program version and exits.
|
|
||||||
|
|
||||||
=item --narrow
|
|
||||||
|
|
||||||
Only edit lines which the user edited.
|
|
||||||
|
|
||||||
If not provided, also edit other lines within at least a 3 line area around
|
|
||||||
the edit, and between any edits within the same hunk.
|
|
||||||
|
|
||||||
=item --version
|
|
||||||
|
|
||||||
Displays program version and exits.
|
|
||||||
|
|
||||||
=back
|
|
||||||
|
|
||||||
=head1 DISTRIBUTION
|
|
||||||
|
|
||||||
Copyright 2005-2020 by Wilson Snyder. This program is free software; you
|
|
||||||
can redistribute it and/or modify it under the terms of either the GNU
|
|
||||||
Lesser General Public License Version 3 or the Perl Artistic License
|
|
||||||
Version 2.0.
|
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
|
||||||
|
|
||||||
=head1 AUTHORS
|
|
||||||
|
|
||||||
Wilson Snyder <[email protected]>
|
|
||||||
|
|
||||||
=head1 SEE ALSO
|
|
||||||
|
|
||||||
=cut
|
|
||||||
|
|
||||||
######################################################################
|
|
||||||
### Local Variables:
|
|
||||||
### compile-command: "./git_untabify "
|
|
||||||
### End:
|
|
||||||
+1
-1
@@ -84,7 +84,7 @@ maintainer-copy::
|
|||||||
clean mostlyclean distclean maintainer-clean::
|
clean mostlyclean distclean maintainer-clean::
|
||||||
-rm -rf obj_* *.log *.dmp *.vpd core
|
-rm -rf obj_* *.log *.dmp *.vpd core
|
||||||
-rm -f *.o *.d perlxsi.c *_gen_*
|
-rm -f *.o *.d perlxsi.c *_gen_*
|
||||||
-rm -f *__gen*
|
-rm -f *__gen* obj_*
|
||||||
-rm -f .objcache*
|
-rm -f .objcache*
|
||||||
|
|
||||||
distclean maintainer-clean::
|
distclean maintainer-clean::
|
||||||
|
|||||||
+12
-6
@@ -42,6 +42,7 @@ LEX = @LEX@
|
|||||||
LFLAGS = -d
|
LFLAGS = -d
|
||||||
PERL = @PERL@
|
PERL = @PERL@
|
||||||
YACC = @YACC@
|
YACC = @YACC@
|
||||||
|
OBJCACHE ?= @OBJCACHE@
|
||||||
|
|
||||||
prefix = @prefix@
|
prefix = @prefix@
|
||||||
|
|
||||||
@@ -167,6 +168,7 @@ RAW_OBJS = \
|
|||||||
V3Cast.o \
|
V3Cast.o \
|
||||||
V3Cdc.o \
|
V3Cdc.o \
|
||||||
V3Changed.o \
|
V3Changed.o \
|
||||||
|
V3Class.o \
|
||||||
V3Clean.o \
|
V3Clean.o \
|
||||||
V3Clock.o \
|
V3Clock.o \
|
||||||
V3Combine.o \
|
V3Combine.o \
|
||||||
@@ -183,6 +185,7 @@ RAW_OBJS = \
|
|||||||
V3EmitCInlines.o \
|
V3EmitCInlines.o \
|
||||||
V3EmitCSyms.o \
|
V3EmitCSyms.o \
|
||||||
V3EmitCMake.o \
|
V3EmitCMake.o \
|
||||||
|
V3EmitCMain.o \
|
||||||
V3EmitMk.o \
|
V3EmitMk.o \
|
||||||
V3EmitV.o \
|
V3EmitV.o \
|
||||||
V3EmitXml.o \
|
V3EmitXml.o \
|
||||||
@@ -208,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 \
|
||||||
@@ -243,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 \
|
||||||
|
|
||||||
@@ -284,21 +290,21 @@ V3Number_test: V3Number_test.o
|
|||||||
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
|
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
|
||||||
|
|
||||||
%.o: %.cpp
|
%.o: %.cpp
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $<
|
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||||
|
|
||||||
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||||
|
|
||||||
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
|
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||||
|
|
||||||
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||||
|
|
||||||
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
||||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||||
|
|
||||||
#### Generated files
|
#### Generated files
|
||||||
|
|
||||||
|
|||||||
+70
-65
@@ -50,11 +50,10 @@ 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
|
||||||
AstActive* m_cActivep; // For current scope, the SActive(combo) we're building
|
AstActive* m_cActivep; // For current scope, the SActive(combo) we're building
|
||||||
|
|
||||||
SenTreeSet m_activeSens; // Sen lists for each active we've made
|
SenTreeSet m_activeSens; // Sen lists for each active we've made
|
||||||
typedef vl_unordered_map<AstSenTree*, AstActive*> ActiveMap;
|
typedef vl_unordered_map<AstSenTree*, AstActive*> ActiveMap;
|
||||||
@@ -89,8 +88,7 @@ public:
|
|||||||
AstActive* getCActive(FileLine* fl) {
|
AstActive* getCActive(FileLine* fl) {
|
||||||
if (!m_cActivep) {
|
if (!m_cActivep) {
|
||||||
m_cActivep = new AstActive(
|
m_cActivep = new AstActive(
|
||||||
fl, "combo",
|
fl, "combo", new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Combo())));
|
||||||
new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Combo())));
|
|
||||||
m_cActivep->sensesStorep(m_cActivep->sensesp());
|
m_cActivep->sensesStorep(m_cActivep->sensesp());
|
||||||
addActive(m_cActivep);
|
addActive(m_cActivep);
|
||||||
}
|
}
|
||||||
@@ -99,8 +97,7 @@ public:
|
|||||||
AstActive* getIActive(FileLine* fl) {
|
AstActive* getIActive(FileLine* fl) {
|
||||||
if (!m_iActivep) {
|
if (!m_iActivep) {
|
||||||
m_iActivep = new AstActive(
|
m_iActivep = new AstActive(
|
||||||
fl, "initial",
|
fl, "initial", new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Initial())));
|
||||||
new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Initial())));
|
|
||||||
m_iActivep->sensesStorep(m_iActivep->sensesp());
|
m_iActivep->sensesStorep(m_iActivep->sensesp());
|
||||||
addActive(m_iActivep);
|
addActive(m_iActivep);
|
||||||
}
|
}
|
||||||
@@ -122,7 +119,7 @@ public:
|
|||||||
AstSenTree* newsenp = sensesp->cloneTree(false);
|
AstSenTree* newsenp = sensesp->cloneTree(false);
|
||||||
activep = new AstActive(fl, "sequent", newsenp);
|
activep = new AstActive(fl, "sequent", newsenp);
|
||||||
activep->sensesStorep(activep->sensesp());
|
activep->sensesStorep(activep->sensesp());
|
||||||
UINFO(8," New ACTIVE "<<activep<<endl);
|
UINFO(8, " New ACTIVE " << activep << endl);
|
||||||
// Form the sensitivity list
|
// Form the sensitivity list
|
||||||
addActive(activep);
|
addActive(activep);
|
||||||
m_activeMap[newsenp] = activep;
|
m_activeMap[newsenp] = activep;
|
||||||
@@ -131,6 +128,7 @@ public:
|
|||||||
}
|
}
|
||||||
return activep;
|
return activep;
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
ActiveNamer() {
|
ActiveNamer() {
|
||||||
@@ -139,9 +137,7 @@ public:
|
|||||||
m_cActivep = NULL;
|
m_cActivep = NULL;
|
||||||
}
|
}
|
||||||
virtual ~ActiveNamer() {}
|
virtual ~ActiveNamer() {}
|
||||||
void main(AstScope* nodep) {
|
void main(AstScope* nodep) { iterate(nodep); }
|
||||||
iterate(nodep);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
@@ -150,27 +146,29 @@ public:
|
|||||||
class ActiveDlyVisitor : public ActiveBaseVisitor {
|
class ActiveDlyVisitor : public ActiveBaseVisitor {
|
||||||
public:
|
public:
|
||||||
enum CheckType { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
|
enum CheckType { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
CheckType m_check; // Combo logic or other
|
CheckType m_check; // Combo logic or other
|
||||||
AstNode* m_alwaysp; // Always we're under
|
AstNode* m_alwaysp; // Always we're under
|
||||||
AstNode* m_assignp; // In assign
|
AstNode* m_assignp; // In assign
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||||
if (m_check != CT_SEQ) {
|
if (m_check != CT_SEQ) {
|
||||||
// Convert to a non-delayed assignment
|
// Convert to a non-delayed assignment
|
||||||
UINFO(5," ASSIGNDLY "<<nodep<<endl);
|
UINFO(5, " ASSIGNDLY " << nodep << endl);
|
||||||
if (m_check == CT_INITIAL) {
|
if (m_check == CT_INITIAL) {
|
||||||
nodep->v3warn(INITIALDLY, "Delayed assignments (<=) in initial or final block\n"
|
nodep->v3warn(INITIALDLY, "Delayed assignments (<=) in initial or final block\n"
|
||||||
<<nodep->warnMore()<<"... Suggest blocking assignments (=)");
|
<< nodep->warnMore()
|
||||||
|
<< "... Suggest blocking assignments (=)");
|
||||||
} else if (m_check == CT_LATCH) {
|
} else if (m_check == CT_LATCH) {
|
||||||
// Suppress. Shouldn't matter that the interior of the latch races
|
// Suppress. Shouldn't matter that the interior of the latch races
|
||||||
} else {
|
} else {
|
||||||
nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked"
|
nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked"
|
||||||
" (non flop or latch) block\n"
|
" (non flop or latch) block\n"
|
||||||
<<nodep->warnMore()<<"... Suggest blocking assignments (=)");
|
<< nodep->warnMore()
|
||||||
|
<< "... Suggest blocking assignments (=)");
|
||||||
}
|
}
|
||||||
AstNode* newp = new AstAssign(nodep->fileline(),
|
AstNode* newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||||
nodep->lhsp()->unlinkFrBack(),
|
|
||||||
nodep->rhsp()->unlinkFrBack());
|
nodep->rhsp()->unlinkFrBack());
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
@@ -186,17 +184,18 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||||
AstVar* varp = nodep->varp();
|
AstVar* varp = nodep->varp();
|
||||||
if (m_check == CT_SEQ
|
if (m_check == CT_SEQ && m_assignp && !varp->isUsedLoopIdx() // Ignore loop indices
|
||||||
&& m_assignp
|
|
||||||
&& !varp->isUsedLoopIdx() // Ignore loop indices
|
|
||||||
&& !varp->isTemp()) {
|
&& !varp->isTemp()) {
|
||||||
// Allow turning off warnings on the always, or the variable also
|
// Allow turning off warnings on the always, or the variable also
|
||||||
if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
||||||
&& !m_assignp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
&& !m_assignp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
||||||
&& !varp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)) {
|
&& !varp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)) {
|
||||||
m_assignp->v3warn(BLKSEQ, "Blocking assignments (=) in sequential (flop or latch) block\n"
|
m_assignp->v3warn(BLKSEQ,
|
||||||
<<m_assignp->warnMore()<<"... Suggest delayed assignments (<=)");
|
"Blocking assignments (=) in sequential (flop or latch) block\n"
|
||||||
m_alwaysp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always
|
<< m_assignp->warnMore()
|
||||||
|
<< "... Suggest delayed assignments (<=)");
|
||||||
|
m_alwaysp->fileline()->modifyWarnOff(
|
||||||
|
V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always
|
||||||
varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true);
|
varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -225,15 +224,15 @@ private:
|
|||||||
// AstNode::user4() Used by V3Const::constify, called below
|
// AstNode::user4() Used by V3Const::constify, called below
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
ActiveNamer m_namer; // Tracking of active names
|
ActiveNamer m_namer; // Tracking of active names
|
||||||
AstCFunc* m_scopeFinalp; // Final function for this scope
|
AstCFunc* m_scopeFinalp; // Final function for this scope
|
||||||
bool m_itemCombo; // Found a SenItem combo
|
bool m_itemCombo; // Found a SenItem combo
|
||||||
bool m_itemSequent; // Found a SenItem sequential
|
bool m_itemSequent; // Found a SenItem sequential
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||||
// Create required actives and add to scope
|
// Create required actives and add to scope
|
||||||
UINFO(4," SCOPE "<<nodep<<endl);
|
UINFO(4, " SCOPE " << nodep << endl);
|
||||||
// Clear last scope's names, and collect this scope's existing names
|
// Clear last scope's names, and collect this scope's existing names
|
||||||
m_namer.main(nodep);
|
m_namer.main(nodep);
|
||||||
m_scopeFinalp = NULL;
|
m_scopeFinalp = NULL;
|
||||||
@@ -244,48 +243,47 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||||
// Relink to IACTIVE, unless already under it
|
// Relink to IACTIVE, unless already under it
|
||||||
UINFO(4," INITIAL "<<nodep<<endl);
|
UINFO(4, " INITIAL " << nodep << endl);
|
||||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
|
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||||
AstActive* wantactivep = m_namer.getIActive(nodep->fileline());
|
AstActive* wantactivep = m_namer.getIActive(nodep->fileline());
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
wantactivep->addStmtsp(nodep);
|
wantactivep->addStmtsp(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||||
// Relink to CACTIVE, unless already under it
|
// Relink to CACTIVE, unless already under it
|
||||||
UINFO(4," ASSIGNW "<<nodep<<endl);
|
UINFO(4, " ASSIGNW " << nodep << endl);
|
||||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
wantactivep->addStmtsp(nodep);
|
wantactivep->addStmtsp(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||||
// Relink to CACTIVE, unless already under it
|
// Relink to CACTIVE, unless already under it
|
||||||
UINFO(4," ASSIGNW "<<nodep<<endl);
|
UINFO(4, " ASSIGNW " << nodep << endl);
|
||||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
wantactivep->addStmtsp(nodep);
|
wantactivep->addStmtsp(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||||
// Relink to CACTIVE, unless already under it
|
// Relink to CACTIVE, unless already under it
|
||||||
UINFO(4," COVERTOGGLE "<<nodep<<endl);
|
UINFO(4, " COVERTOGGLE " << nodep << endl);
|
||||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
wantactivep->addStmtsp(nodep);
|
wantactivep->addStmtsp(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||||
// Relink to CFUNC for the final
|
// Relink to CFUNC for the final
|
||||||
UINFO(4," FINAL "<<nodep<<endl);
|
UINFO(4, " FINAL " << nodep << endl);
|
||||||
if (!nodep->bodysp()) { // Empty, Kill it.
|
if (!nodep->bodysp()) { // Empty, Kill it.
|
||||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
|
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||||
if (!m_scopeFinalp) {
|
if (!m_scopeFinalp) {
|
||||||
m_scopeFinalp = new AstCFunc(
|
m_scopeFinalp = new AstCFunc(
|
||||||
nodep->fileline(), "_final_"+m_namer.scopep()->nameDotless(),
|
nodep->fileline(), "_final_" + m_namer.scopep()->nameDotless(), m_namer.scopep());
|
||||||
m_namer.scopep());
|
|
||||||
m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar());
|
m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||||
m_scopeFinalp->addInitsp(
|
m_scopeFinalp->addInitsp(
|
||||||
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
|
||||||
m_scopeFinalp->dontCombine(true);
|
m_scopeFinalp->dontCombine(true);
|
||||||
m_scopeFinalp->formCallTree(true);
|
m_scopeFinalp->formCallTree(true);
|
||||||
m_scopeFinalp->slow(true);
|
m_scopeFinalp->slow(true);
|
||||||
@@ -300,9 +298,7 @@ private:
|
|||||||
// METHODS
|
// METHODS
|
||||||
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
|
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
|
||||||
// Move always to appropriate ACTIVE based on its sense list
|
// Move always to appropriate ACTIVE based on its sense list
|
||||||
if (oldsensesp
|
if (oldsensesp && oldsensesp->sensesp() && VN_IS(oldsensesp->sensesp(), SenItem)
|
||||||
&& oldsensesp->sensesp()
|
|
||||||
&& VN_IS(oldsensesp->sensesp(), SenItem)
|
|
||||||
&& VN_CAST(oldsensesp->sensesp(), SenItem)->isNever()) {
|
&& VN_CAST(oldsensesp->sensesp(), SenItem)->isNever()) {
|
||||||
// Never executing. Kill it.
|
// Never executing. Kill it.
|
||||||
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
|
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
|
||||||
@@ -318,10 +314,11 @@ private:
|
|||||||
bool combo = m_itemCombo;
|
bool combo = m_itemCombo;
|
||||||
bool sequent = m_itemSequent;
|
bool sequent = m_itemSequent;
|
||||||
|
|
||||||
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()) {
|
if (!v3Global.opt.bboxUnsup()) {
|
||||||
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity (no edge) sensitive activity list");
|
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity "
|
||||||
|
"(no edge) sensitive activity list");
|
||||||
}
|
}
|
||||||
sequent = false;
|
sequent = false;
|
||||||
}
|
}
|
||||||
@@ -336,8 +333,9 @@ private:
|
|||||||
// always (posedge RESET) { if (RESET).... } we know RESET is true.
|
// always (posedge RESET) { if (RESET).... } we know RESET is true.
|
||||||
// Summarize a long list of combo inputs as just "combo"
|
// Summarize a long list of combo inputs as just "combo"
|
||||||
#ifndef __COVERITY__ // Else dead code on next line.
|
#ifndef __COVERITY__ // Else dead code on next line.
|
||||||
if (combo) oldsensesp->addSensesp
|
if (combo) {
|
||||||
(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
|
oldsensesp->addSensesp(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
|
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
|
||||||
}
|
}
|
||||||
@@ -354,19 +352,18 @@ private:
|
|||||||
// Warn and/or convert any delayed assignments
|
// Warn and/or convert any delayed assignments
|
||||||
if (combo && !sequent) {
|
if (combo && !sequent) {
|
||||||
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
|
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
|
||||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_LATCH);
|
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_LATCH);
|
||||||
} else {
|
} else {
|
||||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_COMBO);
|
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_COMBO);
|
||||||
}
|
}
|
||||||
}
|
} else if (!combo && sequent) {
|
||||||
else if (!combo && sequent) {
|
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_SEQ);
|
||||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_SEQ);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||||
// Move always to appropriate ACTIVE based on its sense list
|
// Move always to appropriate ACTIVE based on its sense list
|
||||||
UINFO(4," ALW "<<nodep<<endl);
|
UINFO(4, " ALW " << nodep << endl);
|
||||||
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
|
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
||||||
|
|
||||||
if (!nodep->bodysp()) {
|
if (!nodep->bodysp()) {
|
||||||
// Empty always. Kill it.
|
// Empty always. Kill it.
|
||||||
@@ -377,19 +374,29 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||||
// Move always to appropriate ACTIVE based on its sense list
|
// Move always to appropriate ACTIVE based on its sense list
|
||||||
UINFO(4," ALWPub "<<nodep<<endl);
|
UINFO(4, " ALWPub " << nodep << endl);
|
||||||
//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 {
|
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||||
AstSenItem* subitemp = nodep->sensesp();
|
AstSenItem* subitemp = nodep->sensesp();
|
||||||
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|
||||||
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|
||||||
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
|
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
|
||||||
nodep, "Strange activity type under SenGate");
|
nodep, "Strange activity type under SenGate");
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||||
|
if (nodep->varrefp()) {
|
||||||
|
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
|
||||||
|
if (basicp->isEventValue()) {
|
||||||
|
// Events need to be treated as active high so we only activate on event being
|
||||||
|
// 1
|
||||||
|
UINFO(8, "Demote event to HIGHEDGE " << nodep << endl);
|
||||||
|
nodep->edgeType(VEdgeType::ET_HIGHEDGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) {
|
if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) {
|
||||||
m_itemCombo = true;
|
m_itemCombo = true;
|
||||||
// Delete the sensitivity
|
// Delete the sensitivity
|
||||||
@@ -399,7 +406,7 @@ private:
|
|||||||
// 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->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
||||||
<<nodep->varrefp()->prettyNameQ());
|
<< nodep->varrefp()->prettyNameQ());
|
||||||
}
|
}
|
||||||
m_itemSequent = true;
|
m_itemSequent = true;
|
||||||
nodep->varrefp()->varp()->usedClock(true);
|
nodep->varrefp()->varp()->usedClock(true);
|
||||||
@@ -426,9 +433,7 @@ public:
|
|||||||
// Active class functions
|
// Active class functions
|
||||||
|
|
||||||
void V3Active::activeAll(AstNetlist* nodep) {
|
void V3Active::activeAll(AstNetlist* nodep) {
|
||||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||||
{
|
{ ActiveVisitor visitor(nodep); } // Destruct before checking
|
||||||
ActiveVisitor visitor (nodep);
|
|
||||||
} // Destruct before checking
|
|
||||||
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||||
}
|
}
|
||||||
|
|||||||
+18
-27
@@ -42,11 +42,11 @@ private:
|
|||||||
// AstNode::user() bool. True if processed
|
// AstNode::user() bool. True if processed
|
||||||
// Each call to V3Const::constify
|
// Each call to V3Const::constify
|
||||||
// AstNode::user4() Used by V3Const::constify, called below
|
// AstNode::user4() Used by V3Const::constify, called below
|
||||||
AstUser1InUse m_inuser1;
|
AstUser1InUse m_inuser1;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstTopScope* m_topscopep; // Top scope for adding sentrees under
|
AstTopScope* m_topscopep; // Top scope for adding sentrees under
|
||||||
SenTreeFinder m_finder; // Find global sentree's and add them
|
SenTreeFinder m_finder; // Find global sentree's and add them
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
VL_DEBUG_FUNC; // Declare debug()
|
VL_DEBUG_FUNC; // Declare debug()
|
||||||
@@ -61,16 +61,16 @@ private:
|
|||||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||||
// Create required actives and add to module
|
// Create required actives and add to module
|
||||||
// We can start ordering at a module, or a scope
|
// We can start ordering at a module, or a scope
|
||||||
UINFO(4," MOD "<<nodep<<endl);
|
UINFO(4, " MOD " << nodep << endl);
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||||
UINFO(4," ACTIVE "<<nodep<<endl);
|
UINFO(4, " ACTIVE " << nodep << endl);
|
||||||
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
|
// Remove duplicate clocks and such; sensesp() may change!
|
||||||
|
V3Const::constifyExpensiveEdit(nodep);
|
||||||
AstSenTree* sensesp = nodep->sensesp();
|
AstSenTree* sensesp = nodep->sensesp();
|
||||||
UASSERT_OBJ(sensesp, nodep, "NULL");
|
UASSERT_OBJ(sensesp, nodep, "NULL");
|
||||||
if (sensesp->sensesp()
|
if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem)
|
||||||
&& VN_IS(sensesp->sensesp(), SenItem)
|
|
||||||
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
|
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
|
||||||
// Never executing. Kill it.
|
// Never executing. Kill it.
|
||||||
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
|
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
|
||||||
@@ -80,21 +80,20 @@ private:
|
|||||||
}
|
}
|
||||||
// Copy combo tree to settlement tree with duplicated statements
|
// Copy combo tree to settlement tree with duplicated statements
|
||||||
if (sensesp->hasCombo()) {
|
if (sensesp->hasCombo()) {
|
||||||
AstSenTree* newsentreep
|
AstSenTree* newsentreep = new AstSenTree(
|
||||||
= new AstSenTree(nodep->fileline(),
|
nodep->fileline(), new AstSenItem(nodep->fileline(), AstSenItem::Settle()));
|
||||||
new AstSenItem(nodep->fileline(), AstSenItem::Settle()));
|
AstActive* newp = new AstActive(nodep->fileline(), "settle", newsentreep);
|
||||||
AstActive* newp = new AstActive(nodep->fileline(),"settle", newsentreep);
|
|
||||||
newp->sensesStorep(newsentreep);
|
newp->sensesStorep(newsentreep);
|
||||||
if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true));
|
if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true));
|
||||||
nodep->addNextHere(newp);
|
nodep->addNextHere(newp);
|
||||||
}
|
}
|
||||||
// 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
|
||||||
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
|
UINFO(4, " merge active " << sensesp << " into " << wantp << endl);
|
||||||
if (nodep->sensesStorep()) {
|
if (nodep->sensesStorep()) {
|
||||||
UASSERT_OBJ(sensesp == nodep->sensesStorep(), nodep,
|
UASSERT_OBJ(sensesp == nodep->sensesStorep(), nodep,
|
||||||
"sensesStore should have been deleted earlier if different");
|
"sensesStore should have been deleted earlier if different");
|
||||||
@@ -107,9 +106,9 @@ private:
|
|||||||
nodep->sensesp(wantp);
|
nodep->sensesp(wantp);
|
||||||
}
|
}
|
||||||
// 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
|
||||||
@@ -118,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
|
||||||
@@ -145,9 +138,7 @@ public:
|
|||||||
// Active class functions
|
// Active class functions
|
||||||
|
|
||||||
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
|
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
|
||||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||||
{
|
{ ActiveTopVisitor visitor(nodep); } // Destruct before checking
|
||||||
ActiveTopVisitor visitor (nodep);
|
|
||||||
} // Destruct before checking
|
|
||||||
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||||
}
|
}
|
||||||
|
|||||||
+65
-67
@@ -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
|
||||||
|
|
||||||
@@ -34,30 +31,28 @@ private:
|
|||||||
// NODE STATE/TYPES
|
// NODE STATE/TYPES
|
||||||
// Cleared on netlist
|
// Cleared on netlist
|
||||||
// AstNode::user() -> bool. True if processed
|
// AstNode::user() -> bool. True if processed
|
||||||
AstUser1InUse m_inuser1;
|
AstUser1InUse m_inuser1;
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
AstNodeModule* m_modp; // Last module
|
AstNodeModule* m_modp; // Last module
|
||||||
AstBegin* m_beginp; // Last begin
|
AstBegin* m_beginp; // Last begin
|
||||||
unsigned m_modPastNum; // Module past numbering
|
unsigned m_modPastNum; // Module past numbering
|
||||||
VDouble0 m_statCover; // Statistic tracking
|
VDouble0 m_statCover; // Statistic tracking
|
||||||
VDouble0 m_statAsNotImm; // Statistic tracking
|
VDouble0 m_statAsNotImm; // Statistic tracking
|
||||||
VDouble0 m_statAsImm; // Statistic tracking
|
VDouble0 m_statAsImm; // Statistic tracking
|
||||||
VDouble0 m_statAsFull; // Statistic tracking
|
VDouble0 m_statAsFull; // Statistic tracking
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
|
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
|
||||||
return (string("[%0t] "+prefix+": ")+nodep->fileline()->filebasename()
|
return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":"
|
||||||
+":"+cvtToStr(nodep->fileline()->lineno())
|
+ cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m"
|
||||||
+": Assertion failed in %m"
|
+ ((message != "") ? ": " : "") + message + "\n");
|
||||||
+((message != "")?": ":"")+message
|
|
||||||
+"\n");
|
|
||||||
}
|
}
|
||||||
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
||||||
nodep->displayType(AstDisplayType::DT_WRITE);
|
nodep->displayType(AstDisplayType::DT_WRITE);
|
||||||
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
||||||
// cppcheck-suppress nullPointer
|
// cppcheck-suppress nullPointer
|
||||||
AstNode* timenewp = new AstTime(nodep->fileline());
|
AstNode* timenewp = new AstTime(nodep->fileline(), m_modp->timeunit());
|
||||||
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
|
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
|
||||||
timesp->unlinkFrBackWithNext();
|
timesp->unlinkFrBackWithNext();
|
||||||
timenewp->addNext(timesp);
|
timenewp->addNext(timesp);
|
||||||
@@ -77,8 +72,8 @@ private:
|
|||||||
// If assertions are off, have constant propagation rip them out later
|
// If assertions are off, have constant propagation rip them out later
|
||||||
// This allows syntax errors and such to be detected normally.
|
// This allows syntax errors and such to be detected normally.
|
||||||
(v3Global.opt.assertOn()
|
(v3Global.opt.assertOn()
|
||||||
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
|
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
|
||||||
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
|
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
|
||||||
nodep, NULL);
|
nodep, NULL);
|
||||||
newp->user1(true); // Don't assert/cover this if
|
newp->user1(true); // Don't assert/cover this if
|
||||||
return newp;
|
return newp;
|
||||||
@@ -86,8 +81,8 @@ private:
|
|||||||
|
|
||||||
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
|
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
|
||||||
// Like newFireAssert() but omits the asserts-on check
|
// Like newFireAssert() but omits the asserts-on check
|
||||||
AstDisplay* dispp = new AstDisplay(nodep->fileline(),
|
AstDisplay* dispp
|
||||||
AstDisplayType::DT_ERROR, message, NULL, NULL);
|
= new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL);
|
||||||
AstNode* bodysp = dispp;
|
AstNode* bodysp = dispp;
|
||||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||||
bodysp->addNext(new AstStop(nodep->fileline(), true));
|
bodysp->addNext(new AstStop(nodep->fileline(), true));
|
||||||
@@ -129,7 +124,7 @@ private:
|
|||||||
AstCoverInc* covincp = VN_CAST(snodep->coverincp(), CoverInc);
|
AstCoverInc* covincp = VN_CAST(snodep->coverincp(), CoverInc);
|
||||||
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
|
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
|
||||||
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
||||||
if (message!="") covincp->declp()->comment(message);
|
if (message != "") covincp->declp()->comment(message);
|
||||||
bodysp = covincp;
|
bodysp = covincp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -137,8 +132,11 @@ private:
|
|||||||
ifp = new AstIf(nodep->fileline(), propp, bodysp, NULL);
|
ifp = new AstIf(nodep->fileline(), propp, bodysp, NULL);
|
||||||
bodysp = ifp;
|
bodysp = ifp;
|
||||||
} else if (VN_IS(nodep, Assert)) {
|
} else if (VN_IS(nodep, Assert)) {
|
||||||
if (nodep->immediate()) ++m_statAsImm;
|
if (nodep->immediate()) {
|
||||||
else ++m_statAsNotImm;
|
++m_statAsImm;
|
||||||
|
} else {
|
||||||
|
++m_statAsNotImm;
|
||||||
|
}
|
||||||
if (passsp) passsp = newIfAssertOn(passsp);
|
if (passsp) passsp = newIfAssertOn(passsp);
|
||||||
if (failsp) failsp = newIfAssertOn(failsp);
|
if (failsp) failsp = newIfAssertOn(failsp);
|
||||||
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
||||||
@@ -153,9 +151,10 @@ private:
|
|||||||
|
|
||||||
AstNode* newp;
|
AstNode* newp;
|
||||||
if (sentreep) {
|
if (sentreep) {
|
||||||
newp = new AstAlways(nodep->fileline(),
|
newp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, bodysp);
|
||||||
VAlwaysKwd::ALWAYS, sentreep, bodysp);
|
} else {
|
||||||
} else { newp = bodysp; }
|
newp = bodysp;
|
||||||
|
}
|
||||||
// Install it
|
// Install it
|
||||||
if (selfDestruct) {
|
if (selfDestruct) {
|
||||||
// Delete it after making the tree. This way we can tell the user
|
// Delete it after making the tree. This way we can tell the user
|
||||||
@@ -186,7 +185,7 @@ private:
|
|||||||
iterateAndNextNull(ifp->ifsp());
|
iterateAndNextNull(ifp->ifsp());
|
||||||
|
|
||||||
// If the last else is not an else if, recurse into that too.
|
// If the last else is not an else if, recurse into that too.
|
||||||
if (ifp->elsesp() && !nextifp) {
|
if (ifp->elsesp() && !nextifp) { //
|
||||||
iterateAndNextNull(ifp->elsesp());
|
iterateAndNextNull(ifp->elsesp());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -199,14 +198,12 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Record if this ends with an 'else' that does not have an if
|
// Record if this ends with an 'else' that does not have an if
|
||||||
if (ifp->elsesp() && !nextifp) {
|
if (ifp->elsesp() && !nextifp) hasDefaultElse = true;
|
||||||
hasDefaultElse = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
ifp = nextifp;
|
ifp = nextifp;
|
||||||
} while (ifp);
|
} while (ifp);
|
||||||
|
|
||||||
AstNode *newifp = nodep->cloneTree(false);
|
AstNode* newifp = nodep->cloneTree(false);
|
||||||
bool allow_none = nodep->unique0Pragma();
|
bool allow_none = nodep->unique0Pragma();
|
||||||
|
|
||||||
// Empty case means no property
|
// Empty case means no property
|
||||||
@@ -215,12 +212,11 @@ private:
|
|||||||
// Note: if this ends with an 'else', then we don't need to validate that one of the
|
// Note: if this ends with an 'else', then we don't need to validate that one of the
|
||||||
// predicates evaluates to true.
|
// predicates evaluates to true.
|
||||||
AstNode* ohot = ((allow_none || hasDefaultElse)
|
AstNode* ohot = ((allow_none || hasDefaultElse)
|
||||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||||
AstIf* checkifp = new AstIf(nodep->fileline(),
|
AstIf* checkifp
|
||||||
new AstLogNot(nodep->fileline(), ohot),
|
= new AstIf(nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
|
||||||
newFireAssert(nodep, "'unique if' statement violated"),
|
newFireAssert(nodep, "'unique if' statement violated"), newifp);
|
||||||
newifp);
|
|
||||||
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
|
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||||
nodep->replaceWith(checkifp);
|
nodep->replaceWith(checkifp);
|
||||||
pushDeletep(nodep);
|
pushDeletep(nodep);
|
||||||
@@ -234,16 +230,17 @@ private:
|
|||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (!nodep->user1SetOnce()) {
|
if (!nodep->user1SetOnce()) {
|
||||||
bool has_default = false;
|
bool has_default = false;
|
||||||
for (AstCaseItem* itemp = nodep->itemsp();
|
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||||
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||||
if (itemp->isDefault()) has_default = true;
|
if (itemp->isDefault()) has_default = true;
|
||||||
}
|
}
|
||||||
if (nodep->fullPragma() || nodep->priorityPragma()) {
|
if (nodep->fullPragma() || nodep->priorityPragma()) {
|
||||||
// Simply need to add a default if there isn't one already
|
// Simply need to add a default if there isn't one already
|
||||||
++m_statAsFull;
|
++m_statAsFull;
|
||||||
if (!has_default) {
|
if (!has_default) {
|
||||||
nodep->addItemsp(new AstCaseItem(nodep->fileline(), NULL/*DEFAULT*/,
|
nodep->addItemsp(new AstCaseItem(
|
||||||
newFireAssert(nodep, "synthesis full_case, but non-match found")));
|
nodep->fileline(), NULL /*DEFAULT*/,
|
||||||
|
newFireAssert(nodep, "synthesis full_case, but non-match found")));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
|
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||||
@@ -271,8 +268,11 @@ private:
|
|||||||
nodep->exprp()->cloneTree(false),
|
nodep->exprp()->cloneTree(false),
|
||||||
icondp->cloneTree(false));
|
icondp->cloneTree(false));
|
||||||
}
|
}
|
||||||
if (propp) propp = new AstConcat(icondp->fileline(), onep, propp);
|
if (propp) {
|
||||||
else propp = onep;
|
propp = new AstConcat(icondp->fileline(), onep, propp);
|
||||||
|
} else {
|
||||||
|
propp = onep;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Empty case means no property
|
// Empty case means no property
|
||||||
@@ -281,12 +281,13 @@ private:
|
|||||||
bool allow_none = has_default || nodep->unique0Pragma();
|
bool allow_none = has_default || nodep->unique0Pragma();
|
||||||
AstNode* ohot
|
AstNode* ohot
|
||||||
= (allow_none
|
= (allow_none
|
||||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||||
AstIf* ifp = new AstIf(nodep->fileline(),
|
AstIf* ifp = new AstIf(
|
||||||
new AstLogNot(nodep->fileline(), ohot),
|
nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
|
||||||
newFireAssert(nodep, "synthesis parallel_case, but multiple matches found"),
|
newFireAssert(nodep,
|
||||||
NULL);
|
"synthesis parallel_case, but multiple matches found"),
|
||||||
|
NULL);
|
||||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||||
nodep->addNotParallelp(ifp);
|
nodep->addNotParallelp(ifp);
|
||||||
}
|
}
|
||||||
@@ -303,23 +304,22 @@ private:
|
|||||||
"Expected constant ticks, checked in V3Width");
|
"Expected constant ticks, checked in V3Width");
|
||||||
ticks = VN_CAST(nodep->ticksp(), Const)->toUInt();
|
ticks = VN_CAST(nodep->ticksp(), Const)->toUInt();
|
||||||
}
|
}
|
||||||
UASSERT_OBJ(ticks>=1, nodep, "0 tick should have been checked in V3Width");
|
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
|
||||||
AstNode* inp = nodep->exprp()->unlinkFrBack();
|
AstNode* inp = nodep->exprp()->unlinkFrBack();
|
||||||
AstVar* invarp = NULL;
|
AstVar* invarp = NULL;
|
||||||
AstSenTree* sentreep = nodep->sentreep(); sentreep->unlinkFrBack();
|
AstSenTree* sentreep = nodep->sentreep();
|
||||||
AstAlways* alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS,
|
sentreep->unlinkFrBack();
|
||||||
sentreep, NULL);
|
AstAlways* alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, NULL);
|
||||||
m_modp->addStmtp(alwaysp);
|
m_modp->addStmtp(alwaysp);
|
||||||
for (uint32_t i=0; i<ticks; ++i) {
|
for (uint32_t i = 0; i < ticks; ++i) {
|
||||||
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
|
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
|
||||||
"_Vpast_"+cvtToStr(m_modPastNum++)+"_"+cvtToStr(i),
|
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
|
||||||
inp->dtypep());
|
inp->dtypep());
|
||||||
m_modp->addStmtp(outvarp);
|
m_modp->addStmtp(outvarp);
|
||||||
AstNode* assp = new AstAssignDly(nodep->fileline(),
|
AstNode* assp = new AstAssignDly(nodep->fileline(),
|
||||||
new AstVarRef(nodep->fileline(), outvarp, true),
|
new AstVarRef(nodep->fileline(), outvarp, true), inp);
|
||||||
inp);
|
|
||||||
alwaysp->addStmtp(assp);
|
alwaysp->addStmtp(assp);
|
||||||
//if (debug()>-9) assp->dumpTree(cout, "-ass: ");
|
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
|
||||||
invarp = outvarp;
|
invarp = outvarp;
|
||||||
inp = new AstVarRef(nodep->fileline(), invarp, false);
|
inp = new AstVarRef(nodep->fileline(), invarp, false);
|
||||||
}
|
}
|
||||||
@@ -334,12 +334,12 @@ private:
|
|||||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
// Replace the special types with standard text
|
// Replace the special types with standard text
|
||||||
if (nodep->displayType()==AstDisplayType::DT_INFO) {
|
if (nodep->displayType() == AstDisplayType::DT_INFO) {
|
||||||
replaceDisplay(nodep, "-Info");
|
replaceDisplay(nodep, "-Info");
|
||||||
} else if (nodep->displayType()==AstDisplayType::DT_WARNING) {
|
} else if (nodep->displayType() == AstDisplayType::DT_WARNING) {
|
||||||
replaceDisplay(nodep, "%%Warning");
|
replaceDisplay(nodep, "%%Warning");
|
||||||
} else if (nodep->displayType()==AstDisplayType::DT_ERROR
|
} else if (nodep->displayType() == AstDisplayType::DT_ERROR
|
||||||
|| nodep->displayType()==AstDisplayType::DT_FATAL) {
|
|| nodep->displayType() == AstDisplayType::DT_FATAL) {
|
||||||
replaceDisplay(nodep, "%%Error");
|
replaceDisplay(nodep, "%%Error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -403,9 +403,7 @@ public:
|
|||||||
// Top Assert class
|
// Top Assert class
|
||||||
|
|
||||||
void V3Assert::assertAll(AstNetlist* nodep) {
|
void V3Assert::assertAll(AstNetlist* nodep) {
|
||||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||||
{
|
{ AssertVisitor visitor(nodep); } // Destruct before checking
|
||||||
AssertVisitor visitor (nodep);
|
|
||||||
} // Destruct before checking
|
|
||||||
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-26
@@ -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
|
||||||
|
|
||||||
@@ -61,14 +58,12 @@ private:
|
|||||||
}
|
}
|
||||||
return newp;
|
return newp;
|
||||||
}
|
}
|
||||||
void clearAssertInfo() {
|
void clearAssertInfo() { m_senip = NULL; }
|
||||||
m_senip = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
//========== Statements
|
//========== Statements
|
||||||
virtual void visit(AstClocking* nodep) VL_OVERRIDE {
|
virtual void visit(AstClocking* nodep) VL_OVERRIDE {
|
||||||
UINFO(8," CLOCKING"<<nodep<<endl);
|
UINFO(8, " CLOCKING" << nodep << endl);
|
||||||
// Store the new default clock, reset on new module
|
// Store the new default clock, reset on new module
|
||||||
m_seniDefaultp = nodep->sensesp();
|
m_seniDefaultp = nodep->sensesp();
|
||||||
// Trash it, keeping children
|
// Trash it, keeping children
|
||||||
@@ -81,9 +76,7 @@ private:
|
|||||||
}
|
}
|
||||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||||
iterateAndNextNull(nodep->sensesp());
|
iterateAndNextNull(nodep->sensesp());
|
||||||
if (nodep->sensesp()) {
|
if (nodep->sensesp()) m_seniAlwaysp = nodep->sensesp()->sensesp();
|
||||||
m_seniAlwaysp = nodep->sensesp()->sensesp();
|
|
||||||
}
|
|
||||||
iterateAndNextNull(nodep->bodysp());
|
iterateAndNextNull(nodep->bodysp());
|
||||||
m_seniAlwaysp = NULL;
|
m_seniAlwaysp = NULL;
|
||||||
}
|
}
|
||||||
@@ -93,9 +86,7 @@ private:
|
|||||||
clearAssertInfo();
|
clearAssertInfo();
|
||||||
// Find Clocking's buried under nodep->exprsp
|
// Find Clocking's buried under nodep->exprsp
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
if (!nodep->immediate()) {
|
if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep));
|
||||||
nodep->sentreep(newSenTree(nodep));
|
|
||||||
}
|
|
||||||
clearAssertInfo();
|
clearAssertInfo();
|
||||||
}
|
}
|
||||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||||
@@ -106,21 +97,18 @@ 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) {
|
if (m_senip) nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
|
||||||
nodep->v3error("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()) {
|
||||||
if (VN_IS(nodep->backp(), Cover)) {
|
if (VN_IS(nodep->backp(), Cover)) {
|
||||||
blockp = new AstAnd(nodep->disablep()->fileline(),
|
blockp = new AstAnd(
|
||||||
new AstNot(nodep->disablep()->fileline(),
|
nodep->disablep()->fileline(),
|
||||||
nodep->disablep()->unlinkFrBack()),
|
new AstNot(nodep->disablep()->fileline(), nodep->disablep()->unlinkFrBack()),
|
||||||
blockp);
|
blockp);
|
||||||
} else {
|
} else {
|
||||||
blockp = new AstOr(nodep->disablep()->fileline(),
|
blockp = new AstOr(nodep->disablep()->fileline(),
|
||||||
nodep->disablep()->unlinkFrBack(),
|
nodep->disablep()->unlinkFrBack(), blockp);
|
||||||
blockp);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Unlink and just keep a pointer to it, convert to sentree as needed
|
// Unlink and just keep a pointer to it, convert to sentree as needed
|
||||||
@@ -151,9 +139,7 @@ public:
|
|||||||
// Top Assert class
|
// Top Assert class
|
||||||
|
|
||||||
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
|
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
|
||||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||||
{
|
{ AssertPreVisitor visitor(nodep); } // Destruct before checking
|
||||||
AssertPreVisitor visitor (nodep);
|
|
||||||
} // Destruct before checking
|
|
||||||
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||||
}
|
}
|
||||||
|
|||||||
+277
-232
@@ -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>
|
||||||
|
|
||||||
@@ -51,7 +50,6 @@ bool AstUser5InUse::s_userBusy = false;
|
|||||||
|
|
||||||
int AstNodeDType::s_uniqueNum = 0;
|
int AstNodeDType::s_uniqueNum = 0;
|
||||||
|
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// V3AstType
|
// V3AstType
|
||||||
|
|
||||||
@@ -102,15 +100,16 @@ AstNode* AstNode::abovep() const {
|
|||||||
string AstNode::encodeName(const string& namein) {
|
string AstNode::encodeName(const string& namein) {
|
||||||
// Encode signal name raw from parser, then not called again on same signal
|
// Encode signal name raw from parser, then not called again on same signal
|
||||||
string out;
|
string out;
|
||||||
for (string::const_iterator pos = namein.begin(); pos!=namein.end(); ++pos) {
|
for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) {
|
||||||
if ((pos==namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
|
if ((pos == namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
|
||||||
: isalnum(pos[0])) {
|
: isalnum(pos[0])) {
|
||||||
out += pos[0];
|
out += pos[0];
|
||||||
} else if (pos[0]=='_') {
|
} else if (pos[0] == '_') {
|
||||||
if (pos[1]=='_') {
|
if (pos[1] == '_') {
|
||||||
out += "_"; out += "__05F"; // hex(_) = 0x5F
|
out += "_";
|
||||||
|
out += "__05F"; // hex(_) = 0x5F
|
||||||
++pos;
|
++pos;
|
||||||
if (pos==namein.end()) break;
|
if (pos == namein.end()) break;
|
||||||
} else {
|
} else {
|
||||||
out += pos[0];
|
out += pos[0];
|
||||||
}
|
}
|
||||||
@@ -120,7 +119,8 @@ string AstNode::encodeName(const string& namein) {
|
|||||||
// We also do *NOT* use __DOT__ etc, as we search for those
|
// We also do *NOT* use __DOT__ etc, as we search for those
|
||||||
// in some replacements, and don't want to mangle the user's names.
|
// in some replacements, and don't want to mangle the user's names.
|
||||||
unsigned val = pos[0] & 0xff; // Mask to avoid sign extension
|
unsigned val = pos[0] & 0xff; // Mask to avoid sign extension
|
||||||
char hex[10]; sprintf(hex, "__0%02X", val);
|
char hex[10];
|
||||||
|
sprintf(hex, "__0%02X", val);
|
||||||
out += hex;
|
out += hex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -133,34 +133,26 @@ string AstNode::encodeName(const string& namein) {
|
|||||||
|
|
||||||
string AstNode::encodeNumber(vlsint64_t num) {
|
string AstNode::encodeNumber(vlsint64_t num) {
|
||||||
if (num < 0) {
|
if (num < 0) {
|
||||||
return "__02D"+cvtToStr(-num); // 2D=-
|
return "__02D" + cvtToStr(-num); // 2D=-
|
||||||
} else {
|
} else {
|
||||||
return cvtToStr(num);
|
return cvtToStr(num);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
string AstNode::nameProtect() const {
|
string AstNode::nameProtect() const { return VIdProtect::protectIf(name(), protect()); }
|
||||||
return VIdProtect::protectIf(name(), protect());
|
string AstNode::origNameProtect() const { return VIdProtect::protectIf(origName(), protect()); }
|
||||||
}
|
|
||||||
string AstNode::origNameProtect() const {
|
|
||||||
return VIdProtect::protectIf(origName(), protect());
|
|
||||||
}
|
|
||||||
|
|
||||||
string AstNode::shortName() const {
|
string AstNode::shortName() const {
|
||||||
string pretty = name();
|
string pretty = name();
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
while ((pos = pretty.find("__PVT__")) != string::npos) {
|
while ((pos = pretty.find("__PVT__")) != string::npos) pretty.replace(pos, 7, "");
|
||||||
pretty.replace(pos, 7, "");
|
|
||||||
}
|
|
||||||
return pretty;
|
return pretty;
|
||||||
}
|
}
|
||||||
|
|
||||||
string AstNode::dedotName(const string& namein) {
|
string AstNode::dedotName(const string& namein) {
|
||||||
string pretty = namein;
|
string pretty = namein;
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
while ((pos = pretty.find("__DOT__")) != string::npos) {
|
while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, ".");
|
||||||
pretty.replace(pos, 7, ".");
|
|
||||||
}
|
|
||||||
if (pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
|
if (pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
|
||||||
return pretty;
|
return pretty;
|
||||||
}
|
}
|
||||||
@@ -170,12 +162,8 @@ string AstNode::vcdName(const string& namein) {
|
|||||||
// Dots are reserved for dots the user put in the name
|
// Dots are reserved for dots the user put in the name
|
||||||
string pretty = namein;
|
string pretty = namein;
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
while ((pos = pretty.find("__DOT__")) != string::npos) {
|
while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, " ");
|
||||||
pretty.replace(pos, 7, " ");
|
while ((pos = pretty.find('.')) != string::npos) pretty.replace(pos, 1, " ");
|
||||||
}
|
|
||||||
while ((pos = pretty.find('.')) != string::npos) {
|
|
||||||
pretty.replace(pos, 1, " ");
|
|
||||||
}
|
|
||||||
// Now convert escaped special characters, etc
|
// Now convert escaped special characters, etc
|
||||||
return prettyName(pretty);
|
return prettyName(pretty);
|
||||||
}
|
}
|
||||||
@@ -185,38 +173,38 @@ string AstNode::prettyName(const string& namein) {
|
|||||||
string pretty;
|
string pretty;
|
||||||
pretty = "";
|
pretty = "";
|
||||||
pretty.reserve(namein.length());
|
pretty.reserve(namein.length());
|
||||||
for (const char* pos = namein.c_str(); *pos; ) {
|
for (const char* pos = namein.c_str(); *pos;) {
|
||||||
if (pos[0]=='-' && pos[1]=='>') { // ->
|
if (pos[0] == '-' && pos[1] == '>') { // ->
|
||||||
pretty += ".";
|
pretty += ".";
|
||||||
pos += 2;
|
pos += 2;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pos[0]=='_' && pos[1]=='_') { // Short-circuit
|
if (pos[0] == '_' && pos[1] == '_') { // Short-circuit
|
||||||
if (0==strncmp(pos, "__BRA__", 7)) {
|
if (0 == strncmp(pos, "__BRA__", 7)) {
|
||||||
pretty += "[";
|
pretty += "[";
|
||||||
pos += 7;
|
pos += 7;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (0==strncmp(pos, "__KET__", 7)) {
|
if (0 == strncmp(pos, "__KET__", 7)) {
|
||||||
pretty += "]";
|
pretty += "]";
|
||||||
pos += 7;
|
pos += 7;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (0==strncmp(pos, "__DOT__", 7)) {
|
if (0 == strncmp(pos, "__DOT__", 7)) {
|
||||||
pretty += ".";
|
pretty += ".";
|
||||||
pos += 7;
|
pos += 7;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (0==strncmp(pos, "__PVT__", 7)) {
|
if (0 == strncmp(pos, "__PVT__", 7)) {
|
||||||
pretty += "";
|
pretty += "";
|
||||||
pos += 7;
|
pos += 7;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (pos[0]=='_' && pos[1]=='_' && pos[2]=='0'
|
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && isxdigit(pos[3])
|
||||||
&& isxdigit(pos[3]) && isxdigit(pos[4])) {
|
&& isxdigit(pos[4])) {
|
||||||
char value = 0;
|
char value = 0;
|
||||||
value += 16*(isdigit(pos[3]) ? (pos[3]-'0') : (tolower(pos[3])-'a'+10));
|
value += 16 * (isdigit(pos[3]) ? (pos[3] - '0') : (tolower(pos[3]) - 'a' + 10));
|
||||||
value += (isdigit(pos[4]) ? (pos[4]-'0') : (tolower(pos[4])-'a'+10));
|
value += (isdigit(pos[4]) ? (pos[4] - '0') : (tolower(pos[4]) - 'a' + 10));
|
||||||
pretty += value;
|
pretty += value;
|
||||||
pos += 5;
|
pos += 5;
|
||||||
continue;
|
continue;
|
||||||
@@ -226,37 +214,37 @@ string AstNode::prettyName(const string& namein) {
|
|||||||
pretty += pos[0];
|
pretty += pos[0];
|
||||||
++pos;
|
++pos;
|
||||||
}
|
}
|
||||||
if (pretty[0]=='T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
|
if (pretty[0] == 'T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, "");
|
||||||
if (pretty[0]=='T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, "");
|
if (pretty[0] == 'T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, "");
|
||||||
return pretty;
|
return pretty;
|
||||||
}
|
}
|
||||||
|
|
||||||
string AstNode::prettyTypeName() const {
|
string AstNode::prettyTypeName() const {
|
||||||
if (name()=="") return typeName();
|
if (name() == "") return typeName();
|
||||||
return string(typeName())+" '"+prettyName()+"'";
|
return string(typeName()) + " '" + prettyName() + "'";
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
// Insertion
|
// Insertion
|
||||||
|
|
||||||
inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next) {
|
inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next){
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
// Called on all major tree changers.
|
// Called on all major tree changers.
|
||||||
// Only for use for those really nasty bugs relating to internals
|
// Only for use for those really nasty bugs relating to internals
|
||||||
// Note this may be null.
|
// Note this may be null.
|
||||||
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
|
// if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "
|
||||||
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
// <<prefix<<": "<<cvtToHex(this)<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||||
//if (debug()) {
|
// if (debug()) {
|
||||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||||
// // Commenting out the section below may crash, as the tree state
|
// // Commenting out the section below may crash, as the tree state
|
||||||
// // between edits is not always consistent for printing
|
// // between edits is not always consistent for printing
|
||||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||||
// v3Global.rootp()->dumpTree(cout, "-treeChange: ");
|
// v3Global.rootp()->dumpTree(cout, "-treeChange: ");
|
||||||
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
||||||
// else this->dumpTree(cout, prefix);
|
// else this->dumpTree(cout, prefix);
|
||||||
// this->checkTree();
|
// this->checkTree();
|
||||||
// v3Global.rootp()->checkTree();
|
// v3Global.rootp()->checkTree();
|
||||||
//}
|
//}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -276,8 +264,9 @@ AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
|
|||||||
UDEBUGONLY(UASSERT_OBJ(!oldtailp->m_nextp, nodep,
|
UDEBUGONLY(UASSERT_OBJ(!oldtailp->m_nextp, nodep,
|
||||||
"Node had next, but headtail says it shouldn't"););
|
"Node had next, but headtail says it shouldn't"););
|
||||||
} else {
|
} else {
|
||||||
// Though inefficient, we are occasionally passed a addNext in the middle of a list.
|
// Though inefficient, we are occasionally passed an
|
||||||
while (oldtailp->m_nextp != NULL) oldtailp = oldtailp->m_nextp;
|
// addNext in the middle of a list.
|
||||||
|
while (oldtailp->m_nextp) oldtailp = oldtailp->m_nextp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Link it in
|
// Link it in
|
||||||
@@ -328,15 +317,15 @@ void AstNode::addNextHere(AstNode* newp) {
|
|||||||
AstNode* oldheadtailp = this->m_headtailp;
|
AstNode* oldheadtailp = this->m_headtailp;
|
||||||
// (!oldheadtailp) // this was&is middle of list
|
// (!oldheadtailp) // this was&is middle of list
|
||||||
// (oldheadtailp==this && !oldnext)// this was head AND tail (one node long list)
|
// (oldheadtailp==this && !oldnext)// this was head AND tail (one node long list)
|
||||||
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not tail
|
// (oldheadtailp && oldnextp) // this was&is head of list of not just one node, not
|
||||||
// (oldheadtailp && !oldnextp) // this was tail of list, might also
|
// tail (oldheadtailp && !oldnextp) // this was tail of list, might also
|
||||||
// be head of one-node list
|
// be head of one-node list
|
||||||
//
|
//
|
||||||
newp->m_headtailp = NULL; // Not at head any longer
|
newp->m_headtailp = NULL; // Not at head any longer
|
||||||
addlastp->m_headtailp = NULL; // Presume middle of list
|
addlastp->m_headtailp = NULL; // Presume middle of list
|
||||||
// newp might happen to be head/tail after all, if so will be set again below
|
// newp might happen to be head/tail after all, if so will be set again below
|
||||||
if (oldheadtailp) { // else in middle of list, no change
|
if (oldheadtailp) { // else in middle of list, no change
|
||||||
if (oldheadtailp==this) { // this was one node
|
if (oldheadtailp == this) { // this was one node
|
||||||
this->m_headtailp = addlastp; // Was head/tail, now a tail
|
this->m_headtailp = addlastp; // Was head/tail, now a tail
|
||||||
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL)
|
addlastp->m_headtailp = oldheadtailp; // Tail needs to remember head (or NULL)
|
||||||
} else if (!oldnextp) { // this was tail
|
} else if (!oldnextp) { // this was tail
|
||||||
@@ -404,26 +393,38 @@ void AstNode::setOp4p(AstNode* newp) {
|
|||||||
|
|
||||||
void AstNode::addOp1p(AstNode* newp) {
|
void AstNode::addOp1p(AstNode* newp) {
|
||||||
UASSERT(newp, "Null item passed to addOp1p");
|
UASSERT(newp, "Null item passed to addOp1p");
|
||||||
if (!m_op1p) { op1p(newp); }
|
if (!m_op1p) {
|
||||||
else { m_op1p->addNext(newp); }
|
op1p(newp);
|
||||||
|
} else {
|
||||||
|
m_op1p->addNext(newp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::addOp2p(AstNode* newp) {
|
void AstNode::addOp2p(AstNode* newp) {
|
||||||
UASSERT(newp, "Null item passed to addOp2p");
|
UASSERT(newp, "Null item passed to addOp2p");
|
||||||
if (!m_op2p) { op2p(newp); }
|
if (!m_op2p) {
|
||||||
else { m_op2p->addNext(newp); }
|
op2p(newp);
|
||||||
|
} else {
|
||||||
|
m_op2p->addNext(newp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::addOp3p(AstNode* newp) {
|
void AstNode::addOp3p(AstNode* newp) {
|
||||||
UASSERT(newp, "Null item passed to addOp3p");
|
UASSERT(newp, "Null item passed to addOp3p");
|
||||||
if (!m_op3p) { op3p(newp); }
|
if (!m_op3p) {
|
||||||
else { m_op3p->addNext(newp); }
|
op3p(newp);
|
||||||
|
} else {
|
||||||
|
m_op3p->addNext(newp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::addOp4p(AstNode* newp) {
|
void AstNode::addOp4p(AstNode* newp) {
|
||||||
UASSERT(newp, "Null item passed to addOp4p");
|
UASSERT(newp, "Null item passed to addOp4p");
|
||||||
if (!m_op4p) { op4p(newp); }
|
if (!m_op4p) {
|
||||||
else { m_op4p->addNext(newp); }
|
op4p(newp);
|
||||||
|
} else {
|
||||||
|
m_op4p->addNext(newp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::replaceWith(AstNode* newp) {
|
void AstNode::replaceWith(AstNode* newp) {
|
||||||
@@ -435,13 +436,13 @@ void AstNode::replaceWith(AstNode* newp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AstNRelinker::dump(std::ostream& str) const {
|
void AstNRelinker::dump(std::ostream& str) const {
|
||||||
str<<" BK="<<reinterpret_cast<uint32_t*>(m_backp);
|
str << " BK=" << reinterpret_cast<uint32_t*>(m_backp);
|
||||||
str<<" ITER="<<reinterpret_cast<uint32_t*>(m_iterpp);
|
str << " ITER=" << reinterpret_cast<uint32_t*>(m_iterpp);
|
||||||
str<<" CHG="<<(m_chg==RELINK_NEXT?"[NEXT] ":"");
|
str << " CHG=" << (m_chg == RELINK_NEXT ? "[NEXT] " : "");
|
||||||
str<<(m_chg==RELINK_OP1?"[OP1] ":"");
|
str << (m_chg == RELINK_OP1 ? "[OP1] " : "");
|
||||||
str<<(m_chg==RELINK_OP2?"[OP2] ":"");
|
str << (m_chg == RELINK_OP2 ? "[OP2] " : "");
|
||||||
str<<(m_chg==RELINK_OP3?"[OP3] ":"");
|
str << (m_chg == RELINK_OP3 ? "[OP3] " : "");
|
||||||
str<<(m_chg==RELINK_OP4?"[OP4] ":"");
|
str << (m_chg == RELINK_OP4 ? "[OP4] " : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
||||||
@@ -452,17 +453,24 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
|||||||
AstNode* backp = oldp->m_backp;
|
AstNode* backp = oldp->m_backp;
|
||||||
if (linkerp) {
|
if (linkerp) {
|
||||||
linkerp->m_oldp = oldp;
|
linkerp->m_oldp = oldp;
|
||||||
linkerp->m_backp = backp;
|
linkerp->m_backp = backp;
|
||||||
linkerp->m_iterpp = oldp->m_iterpp;
|
linkerp->m_iterpp = oldp->m_iterpp;
|
||||||
if (backp->m_nextp == oldp) linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
if (backp->m_nextp == oldp) {
|
||||||
else if (backp->m_op1p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
||||||
else if (backp->m_op2p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
} else if (backp->m_op1p == oldp) {
|
||||||
else if (backp->m_op3p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
||||||
else if (backp->m_op4p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
} else if (backp->m_op2p == oldp) {
|
||||||
else oldp->v3fatalSrc("Unlink of node with back not pointing to it.");
|
linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
||||||
|
} else if (backp->m_op3p == oldp) {
|
||||||
|
linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
||||||
|
} else if (backp->m_op4p == oldp) {
|
||||||
|
linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
||||||
|
} else {
|
||||||
|
oldp->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (backp->m_nextp== oldp) {
|
if (backp->m_nextp == oldp) {
|
||||||
backp->m_nextp= NULL;
|
backp->m_nextp = NULL;
|
||||||
// Old list gets truncated
|
// Old list gets truncated
|
||||||
// New list becomes a list upon itself
|
// New list becomes a list upon itself
|
||||||
// Most common case is unlinking a entire operand tree
|
// Most common case is unlinking a entire operand tree
|
||||||
@@ -477,12 +485,17 @@ AstNode* AstNode::unlinkFrBackWithNext(AstNRelinker* linkerp) {
|
|||||||
// Create new head/tail of extracted list
|
// Create new head/tail of extracted list
|
||||||
oldp->m_headtailp = oldtailp;
|
oldp->m_headtailp = oldtailp;
|
||||||
oldp->m_headtailp->m_headtailp = oldp;
|
oldp->m_headtailp->m_headtailp = oldp;
|
||||||
|
} else if (backp->m_op1p == oldp) {
|
||||||
|
backp->m_op1p = NULL;
|
||||||
|
} else if (backp->m_op2p == oldp) {
|
||||||
|
backp->m_op2p = NULL;
|
||||||
|
} else if (backp->m_op3p == oldp) {
|
||||||
|
backp->m_op3p = NULL;
|
||||||
|
} else if (backp->m_op4p == oldp) {
|
||||||
|
backp->m_op4p = NULL;
|
||||||
|
} else {
|
||||||
|
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||||
}
|
}
|
||||||
else if (backp->m_op1p == oldp) backp->m_op1p = NULL;
|
|
||||||
else if (backp->m_op2p == oldp) backp->m_op2p = NULL;
|
|
||||||
else if (backp->m_op3p == oldp) backp->m_op3p = NULL;
|
|
||||||
else if (backp->m_op4p == oldp) backp->m_op4p = NULL;
|
|
||||||
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
|
||||||
// Relink
|
// Relink
|
||||||
oldp->m_backp = NULL;
|
oldp->m_backp = NULL;
|
||||||
// Iterator fixup
|
// Iterator fixup
|
||||||
@@ -500,32 +513,44 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
|||||||
AstNode* backp = oldp->m_backp;
|
AstNode* backp = oldp->m_backp;
|
||||||
if (linkerp) {
|
if (linkerp) {
|
||||||
linkerp->m_oldp = oldp;
|
linkerp->m_oldp = oldp;
|
||||||
linkerp->m_backp = backp;
|
linkerp->m_backp = backp;
|
||||||
linkerp->m_iterpp = oldp->m_iterpp;
|
linkerp->m_iterpp = oldp->m_iterpp;
|
||||||
if (backp->m_nextp == oldp) linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
if (backp->m_nextp == oldp) {
|
||||||
else if (backp->m_op1p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
linkerp->m_chg = AstNRelinker::RELINK_NEXT;
|
||||||
else if (backp->m_op2p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
} else if (backp->m_op1p == oldp) {
|
||||||
else if (backp->m_op3p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
linkerp->m_chg = AstNRelinker::RELINK_OP1;
|
||||||
else if (backp->m_op4p == oldp) linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
} else if (backp->m_op2p == oldp) {
|
||||||
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
linkerp->m_chg = AstNRelinker::RELINK_OP2;
|
||||||
|
} else if (backp->m_op3p == oldp) {
|
||||||
|
linkerp->m_chg = AstNRelinker::RELINK_OP3;
|
||||||
|
} else if (backp->m_op4p == oldp) {
|
||||||
|
linkerp->m_chg = AstNRelinker::RELINK_OP4;
|
||||||
|
} else {
|
||||||
|
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (backp->m_nextp== oldp) {
|
if (backp->m_nextp == oldp) {
|
||||||
// This node gets removed from middle (or tail) of list
|
// This node gets removed from middle (or tail) of list
|
||||||
// Not head, since then oldp wouldn't be a next of backp...
|
// Not head, since then oldp wouldn't be a next of backp...
|
||||||
backp->m_nextp= oldp->m_nextp;
|
backp->m_nextp = oldp->m_nextp;
|
||||||
if (backp->m_nextp) backp->m_nextp->m_backp = backp;
|
if (backp->m_nextp) backp->m_nextp->m_backp = backp;
|
||||||
// If it was a tail, back becomes new tail
|
// If it was a tail, back becomes new tail
|
||||||
if (oldp->m_headtailp) {
|
if (oldp->m_headtailp) {
|
||||||
backp->m_headtailp = oldp->m_headtailp;
|
backp->m_headtailp = oldp->m_headtailp;
|
||||||
backp->m_headtailp->m_headtailp = backp;
|
backp->m_headtailp->m_headtailp = backp;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
if (backp->m_op1p == oldp) {
|
||||||
if (backp->m_op1p == oldp) backp->m_op1p = oldp->m_nextp;
|
backp->m_op1p = oldp->m_nextp;
|
||||||
else if (backp->m_op2p == oldp) backp->m_op2p = oldp->m_nextp;
|
} else if (backp->m_op2p == oldp) {
|
||||||
else if (backp->m_op3p == oldp) backp->m_op3p = oldp->m_nextp;
|
backp->m_op2p = oldp->m_nextp;
|
||||||
else if (backp->m_op4p == oldp) backp->m_op4p = oldp->m_nextp;
|
} else if (backp->m_op3p == oldp) {
|
||||||
else this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
backp->m_op3p = oldp->m_nextp;
|
||||||
|
} else if (backp->m_op4p == oldp) {
|
||||||
|
backp->m_op4p = oldp->m_nextp;
|
||||||
|
} else {
|
||||||
|
this->v3fatalSrc("Unlink of node with back not pointing to it.");
|
||||||
|
}
|
||||||
if (oldp->m_nextp) {
|
if (oldp->m_nextp) {
|
||||||
AstNode* newheadp = oldp->m_nextp;
|
AstNode* newheadp = oldp->m_nextp;
|
||||||
newheadp->m_backp = backp;
|
newheadp->m_backp = backp;
|
||||||
@@ -545,13 +570,19 @@ AstNode* AstNode::unlinkFrBack(AstNRelinker* linkerp) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::relink(AstNRelinker* linkerp) {
|
void AstNode::relink(AstNRelinker* linkerp) {
|
||||||
if (debug()>8) { UINFO(0," EDIT: relink: "); dumpPtrs(); }
|
if (debug() > 8) {
|
||||||
|
UINFO(0, " EDIT: relink: ");
|
||||||
|
dumpPtrs();
|
||||||
|
}
|
||||||
AstNode* newp = this;
|
AstNode* newp = this;
|
||||||
UASSERT(linkerp && linkerp->m_backp, "Need non-empty linker");
|
UASSERT(linkerp && linkerp->m_backp, "Need non-empty linker");
|
||||||
UASSERT(!newp->backp(), "New node already linked?");
|
UASSERT(!newp->backp(), "New node already linked?");
|
||||||
newp->editCountInc();
|
newp->editCountInc();
|
||||||
|
|
||||||
if (debug()>8) { linkerp->dump(cout); cout<<endl; }
|
if (debug() > 8) {
|
||||||
|
linkerp->dump(cout);
|
||||||
|
cout << endl;
|
||||||
|
}
|
||||||
|
|
||||||
AstNode* backp = linkerp->m_backp;
|
AstNode* backp = linkerp->m_backp;
|
||||||
this->debugTreeChange("-relinkNew: ", __LINE__, true);
|
this->debugTreeChange("-relinkNew: ", __LINE__, true);
|
||||||
@@ -563,9 +594,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
|||||||
case AstNRelinker::RELINK_OP2: relinkOneLink(backp->m_op2p /*ref*/, newp); break;
|
case AstNRelinker::RELINK_OP2: relinkOneLink(backp->m_op2p /*ref*/, newp); break;
|
||||||
case AstNRelinker::RELINK_OP3: relinkOneLink(backp->m_op3p /*ref*/, newp); break;
|
case AstNRelinker::RELINK_OP3: relinkOneLink(backp->m_op3p /*ref*/, newp); break;
|
||||||
case AstNRelinker::RELINK_OP4: relinkOneLink(backp->m_op4p /*ref*/, newp); break;
|
case AstNRelinker::RELINK_OP4: relinkOneLink(backp->m_op4p /*ref*/, newp); break;
|
||||||
default:
|
default: this->v3fatalSrc("Relink of node without any link to change."); break;
|
||||||
this->v3fatalSrc("Relink of node without any link to change.");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
// Relink
|
// Relink
|
||||||
newp->m_backp = backp;
|
newp->m_backp = backp;
|
||||||
@@ -595,10 +624,10 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
|
|||||||
// Insert the whole old list following the new node's list.
|
// Insert the whole old list following the new node's list.
|
||||||
// Thus a unlink without next, followed by relink, gives the same list.
|
// Thus a unlink without next, followed by relink, gives the same list.
|
||||||
AstNode* newlistlastp = newp->m_headtailp;
|
AstNode* newlistlastp = newp->m_headtailp;
|
||||||
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp!=newp), newp,
|
UASSERT_OBJ(!(newlistlastp->m_nextp && newlistlastp != newp), newp,
|
||||||
"Headtailp tail isn't at the tail");
|
"Headtailp tail isn't at the tail");
|
||||||
AstNode* oldlistlastp = pointpr->m_headtailp;
|
AstNode* oldlistlastp = pointpr->m_headtailp;
|
||||||
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp!=pointpr), newp,
|
UASSERT_OBJ(!(oldlistlastp->m_nextp && oldlistlastp != pointpr), newp,
|
||||||
"Old headtailp tail isn't at the tail");
|
"Old headtailp tail isn't at the tail");
|
||||||
// Next links
|
// Next links
|
||||||
newlistlastp->m_nextp = pointpr;
|
newlistlastp->m_nextp = pointpr;
|
||||||
@@ -650,7 +679,7 @@ AstNode* AstNode::cloneTreeIterList() {
|
|||||||
AstNode* newheadp = NULL;
|
AstNode* newheadp = NULL;
|
||||||
AstNode* newtailp = NULL;
|
AstNode* newtailp = NULL;
|
||||||
// Audited to make sure this is never NULL
|
// Audited to make sure this is never NULL
|
||||||
for (AstNode* oldp = this; oldp; oldp=oldp->m_nextp) {
|
for (AstNode* oldp = this; oldp; oldp = oldp->m_nextp) {
|
||||||
AstNode* newp = oldp->cloneTreeIter();
|
AstNode* newp = oldp->cloneTreeIter();
|
||||||
newp->m_headtailp = NULL;
|
newp->m_headtailp = NULL;
|
||||||
newp->m_backp = newtailp;
|
newp->m_backp = newtailp;
|
||||||
@@ -697,11 +726,11 @@ 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
|
||||||
) {
|
) {
|
||||||
delete this;
|
delete this;
|
||||||
}
|
}
|
||||||
// Else leak massively, so each pointer is unique
|
// Else leak massively, so each pointer is unique
|
||||||
@@ -711,7 +740,7 @@ void AstNode::deleteNode() {
|
|||||||
void AstNode::deleteTreeIter() {
|
void AstNode::deleteTreeIter() {
|
||||||
// private: Delete list of nodes. Publicly call deleteTree() instead.
|
// private: Delete list of nodes. Publicly call deleteTree() instead.
|
||||||
// Audited to make sure this is never NULL
|
// Audited to make sure this is never NULL
|
||||||
for (AstNode* nodep=this, *nnextp; nodep; nodep=nnextp) {
|
for (AstNode *nodep = this, *nnextp; nodep; nodep = nnextp) {
|
||||||
nnextp = nodep->m_nextp;
|
nnextp = nodep->m_nextp;
|
||||||
// MUST be depth first!
|
// MUST be depth first!
|
||||||
if (nodep->m_op1p) nodep->m_op1p->deleteTreeIter();
|
if (nodep->m_op1p) nodep->m_op1p->deleteTreeIter();
|
||||||
@@ -789,26 +818,25 @@ void AstNode::iterateAndNext(AstNVisitor& v) {
|
|||||||
// there's no lower level reason yet though the back must exist.
|
// there's no lower level reason yet though the back must exist.
|
||||||
AstNode* nodep = this;
|
AstNode* nodep = this;
|
||||||
#ifdef VL_DEBUG // Otherwise too hot of a function for debug
|
#ifdef VL_DEBUG // Otherwise too hot of a function for debug
|
||||||
UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep,
|
UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep, "iterateAndNext node has no back");
|
||||||
"iterateAndNext node has no back");
|
|
||||||
#endif
|
#endif
|
||||||
if (nodep) ASTNODE_PREFETCH(nodep->m_nextp);
|
if (nodep) ASTNODE_PREFETCH(nodep->m_nextp);
|
||||||
while (nodep) { // effectively: if (!this) return; // Callers rely on this
|
while (nodep) { // effectively: if (!this) return; // Callers rely on this
|
||||||
if (nodep->m_nextp) ASTNODE_PREFETCH(nodep->m_nextp->m_nextp);
|
if (nodep->m_nextp) ASTNODE_PREFETCH(nodep->m_nextp->m_nextp);
|
||||||
AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited
|
AstNode* niterp = nodep; // Pointer may get stomped via m_iterpp if the node is edited
|
||||||
// Desirable check, but many places where multiple iterations are OK
|
// Desirable check, but many places where multiple iterations are OK
|
||||||
// UASSERT_OBJ(!niterp->m_iterpp, niterp, "IterateAndNext under iterateAndNext may miss edits");
|
// UASSERT_OBJ(!niterp->m_iterpp, niterp, "IterateAndNext under iterateAndNext may miss
|
||||||
// Optimization note: Doing PREFETCH_RW on m_iterpp is a net even
|
// edits"); Optimization note: Doing PREFETCH_RW on m_iterpp is a net even
|
||||||
// cppcheck-suppress nullPointer
|
// cppcheck-suppress nullPointer
|
||||||
niterp->m_iterpp = &niterp;
|
niterp->m_iterpp = &niterp;
|
||||||
niterp->accept(v);
|
niterp->accept(v);
|
||||||
// accept may do a replaceNode and change niterp on us...
|
// accept may do a replaceNode and change niterp on us...
|
||||||
// niterp maybe NULL, so need cast if printing
|
// niterp maybe NULL, so need cast if printing
|
||||||
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<cvtToHex(nodep)
|
// if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<cvtToHex(nodep)
|
||||||
// <<" now into "<<cvtToHex(niterp)<<endl);
|
// <<" now into "<<cvtToHex(niterp)<<endl);
|
||||||
if (!niterp) return; // Perhaps node deleted inside accept
|
if (!niterp) return; // Perhaps node deleted inside accept
|
||||||
niterp->m_iterpp = NULL;
|
niterp->m_iterpp = NULL;
|
||||||
if (VL_UNLIKELY(niterp!=nodep)) { // Edited node inside accept
|
if (VL_UNLIKELY(niterp != nodep)) { // Edited node inside accept
|
||||||
nodep = niterp;
|
nodep = niterp;
|
||||||
} else { // Unchanged node, just continue loop
|
} else { // Unchanged node, just continue loop
|
||||||
nodep = niterp->m_nextp;
|
nodep = niterp->m_nextp;
|
||||||
@@ -822,8 +850,11 @@ void AstNode::iterateListBackwards(AstNVisitor& v) {
|
|||||||
while (nodep) {
|
while (nodep) {
|
||||||
// Edits not supported: nodep->m_iterpp = &nodep;
|
// Edits not supported: nodep->m_iterpp = &nodep;
|
||||||
nodep->accept(v);
|
nodep->accept(v);
|
||||||
if (nodep->backp()->m_nextp == nodep) nodep = nodep->backp();
|
if (nodep->backp()->m_nextp == nodep) {
|
||||||
else nodep = NULL; // else: backp points up the tree.
|
nodep = nodep->backp();
|
||||||
|
} else {
|
||||||
|
nodep = NULL;
|
||||||
|
} // else: backp points up the tree.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,7 +892,8 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||||||
// track, then delete it on completion
|
// track, then delete it on completion
|
||||||
AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
|
AstBegin* tempp = new AstBegin(nodep->fileline(), "[EditWrapper]", nodep);
|
||||||
{
|
{
|
||||||
VL_DO_DANGLING(tempp->stmtsp()->accept(v), nodep); // nodep to null as may be replaced
|
VL_DO_DANGLING(tempp->stmtsp()->accept(v),
|
||||||
|
nodep); // nodep to null as may be replaced
|
||||||
}
|
}
|
||||||
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
|
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
|
||||||
VL_DO_DANGLING(tempp->deleteTree(), tempp);
|
VL_DO_DANGLING(tempp->deleteTree(), tempp);
|
||||||
@@ -869,11 +901,17 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||||||
// Use back to determine who's pointing at us (IE assume new node
|
// Use back to determine who's pointing at us (IE assume new node
|
||||||
// grafts into same place as old one)
|
// grafts into same place as old one)
|
||||||
AstNode** nextnodepp = NULL;
|
AstNode** nextnodepp = NULL;
|
||||||
if (this->m_backp->m_op1p == this) nextnodepp = &(this->m_backp->m_op1p);
|
if (this->m_backp->m_op1p == this) {
|
||||||
else if (this->m_backp->m_op2p == this) nextnodepp = &(this->m_backp->m_op2p);
|
nextnodepp = &(this->m_backp->m_op1p);
|
||||||
else if (this->m_backp->m_op3p == this) nextnodepp = &(this->m_backp->m_op3p);
|
} else if (this->m_backp->m_op2p == this) {
|
||||||
else if (this->m_backp->m_op4p == this) nextnodepp = &(this->m_backp->m_op4p);
|
nextnodepp = &(this->m_backp->m_op2p);
|
||||||
else if (this->m_backp->m_nextp == this) nextnodepp = &(this->m_backp->m_nextp);
|
} else if (this->m_backp->m_op3p == this) {
|
||||||
|
nextnodepp = &(this->m_backp->m_op3p);
|
||||||
|
} else if (this->m_backp->m_op4p == this) {
|
||||||
|
nextnodepp = &(this->m_backp->m_op4p);
|
||||||
|
} else if (this->m_backp->m_nextp == this) {
|
||||||
|
nextnodepp = &(this->m_backp->m_nextp);
|
||||||
|
}
|
||||||
UASSERT_OBJ(nextnodepp, this, "Node's back doesn't point to forward to node itself");
|
UASSERT_OBJ(nextnodepp, this, "Node's back doesn't point to forward to node itself");
|
||||||
{
|
{
|
||||||
VL_DO_DANGLING(nodep->accept(v), nodep); // nodep to null as may be replaced
|
VL_DO_DANGLING(nodep->accept(v), nodep); // nodep to null as may be replaced
|
||||||
@@ -887,10 +925,8 @@ AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
|||||||
|
|
||||||
void AstNode::cloneRelinkTree() {
|
void AstNode::cloneRelinkTree() {
|
||||||
// private: Cleanup clone() operation on whole tree. Publicly call cloneTree() instead.
|
// private: Cleanup clone() operation on whole tree. Publicly call cloneTree() instead.
|
||||||
for (AstNode* nodep=this; nodep; nodep = nodep->m_nextp) {
|
for (AstNode* nodep = this; nodep; nodep = nodep->m_nextp) {
|
||||||
if (m_dtypep && m_dtypep->clonep()) {
|
if (m_dtypep && m_dtypep->clonep()) m_dtypep = m_dtypep->clonep();
|
||||||
m_dtypep = m_dtypep->clonep();
|
|
||||||
}
|
|
||||||
nodep->cloneRelink();
|
nodep->cloneRelink();
|
||||||
if (nodep->m_op1p) nodep->m_op1p->cloneRelinkTree();
|
if (nodep->m_op1p) nodep->m_op1p->cloneRelinkTree();
|
||||||
if (nodep->m_op2p) nodep->m_op2p->cloneRelinkTree();
|
if (nodep->m_op2p) nodep->m_op2p->cloneRelinkTree();
|
||||||
@@ -912,37 +948,34 @@ bool AstNode::gateTreeIter() const {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p,
|
bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
|
||||||
bool ignNext, bool gateOnly) {
|
bool gateOnly) {
|
||||||
// private: Return true if the two trees are identical
|
// private: Return true if the two trees are identical
|
||||||
if (!node1p && !node2p) return true;
|
if (!node1p && !node2p) return true;
|
||||||
if (!node1p || !node2p) return false;
|
if (!node1p || !node2p) return false;
|
||||||
if (node1p->type() != node2p->type()
|
if (node1p->type() != node2p->type() || node1p->dtypep() != node2p->dtypep()
|
||||||
|| node1p->dtypep() != node2p->dtypep()
|
|| !node1p->same(node2p) || (gateOnly && !node1p->isGateOptimizable())) {
|
||||||
|| !node1p->same(node2p)
|
|
||||||
|| (gateOnly && !node1p->isGateOptimizable())) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (sameTreeIter(node1p->m_op1p, node2p->m_op1p, false, gateOnly)
|
return (sameTreeIter(node1p->m_op1p, node2p->m_op1p, false, gateOnly)
|
||||||
&& sameTreeIter(node1p->m_op2p, node2p->m_op2p, false, gateOnly)
|
&& sameTreeIter(node1p->m_op2p, node2p->m_op2p, false, gateOnly)
|
||||||
&& sameTreeIter(node1p->m_op3p, node2p->m_op3p, false, gateOnly)
|
&& sameTreeIter(node1p->m_op3p, node2p->m_op3p, false, gateOnly)
|
||||||
&& sameTreeIter(node1p->m_op4p, node2p->m_op4p, false, gateOnly)
|
&& sameTreeIter(node1p->m_op4p, node2p->m_op4p, false, gateOnly)
|
||||||
&& (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly))
|
&& (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly)));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Static utilities
|
// Static utilities
|
||||||
|
|
||||||
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) {
|
std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) {
|
||||||
return os<<std::hex<<std::setw(2)<<std::setfill('0')<<rhs.depth()
|
return os << std::hex << std::setw(2) << std::setfill('0') << rhs.depth() << "_"
|
||||||
<<"_"<<std::setw(6)<<std::setfill('0')<<rhs.hshval();
|
<< std::setw(6) << std::setfill('0') << rhs.hshval();
|
||||||
}
|
}
|
||||||
|
|
||||||
V3Hash::V3Hash(const string& name) {
|
V3Hash::V3Hash(const string& name) {
|
||||||
uint32_t val = 0;
|
uint32_t val = 0;
|
||||||
for (string::const_iterator it = name.begin(); it!=name.end(); ++it) {
|
for (string::const_iterator it = name.begin(); it != name.end(); ++it) {
|
||||||
val = val*31 + *it;
|
val = val * 31 + *it;
|
||||||
}
|
}
|
||||||
setBoth(1, val);
|
setBoth(1, val);
|
||||||
}
|
}
|
||||||
@@ -955,7 +988,7 @@ void AstNode::checkTreeIter(AstNode* backp) {
|
|||||||
UASSERT_OBJ(backp == this->backp(), this, "Back node inconsistent");
|
UASSERT_OBJ(backp == this->backp(), this, "Back node inconsistent");
|
||||||
if (VN_IS(this, NodeTermop) || VN_IS(this, NodeVarRef)) {
|
if (VN_IS(this, NodeTermop) || VN_IS(this, NodeVarRef)) {
|
||||||
// Termops have a short-circuited iterateChildren, so check usage
|
// Termops have a short-circuited iterateChildren, so check usage
|
||||||
UASSERT_OBJ(!(op1p()||op2p()||op3p()||op4p()), this,
|
UASSERT_OBJ(!(op1p() || op2p() || op3p() || op4p()), this,
|
||||||
"Terminal operation with non-terminals");
|
"Terminal operation with non-terminals");
|
||||||
}
|
}
|
||||||
if (m_op1p) m_op1p->checkTreeIterList(this);
|
if (m_op1p) m_op1p->checkTreeIterList(this);
|
||||||
@@ -969,9 +1002,9 @@ void AstNode::checkTreeIterList(AstNode* backp) {
|
|||||||
// Audited to make sure this is never NULL
|
// Audited to make sure this is never NULL
|
||||||
AstNode* headp = this;
|
AstNode* headp = this;
|
||||||
AstNode* tailp = this;
|
AstNode* tailp = this;
|
||||||
for (AstNode* nodep=headp; nodep; nodep=nodep->nextp()) {
|
for (AstNode* nodep = headp; nodep; nodep = nodep->nextp()) {
|
||||||
nodep->checkTreeIter(backp);
|
nodep->checkTreeIter(backp);
|
||||||
UASSERT_OBJ(headp==this || !nextp(), this,
|
UASSERT_OBJ(headp == this || !nextp(), this,
|
||||||
"Headtailp should be null in middle of lists");
|
"Headtailp should be null in middle of lists");
|
||||||
tailp = nodep;
|
tailp = nodep;
|
||||||
backp = nodep;
|
backp = nodep;
|
||||||
@@ -993,12 +1026,14 @@ void AstNode::checkTree() {
|
|||||||
// cppcheck-suppress unusedFunction // Debug only
|
// cppcheck-suppress unusedFunction // Debug only
|
||||||
void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE
|
void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE
|
||||||
dumpGdbHeader(); // LCOV_EXCL_LINE
|
dumpGdbHeader(); // LCOV_EXCL_LINE
|
||||||
cout<<" "; dump(cout); cout<<endl; // LCOV_EXCL_LINE
|
cout << " ";
|
||||||
|
dump(cout);
|
||||||
|
cout << endl; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
// cppcheck-suppress unusedFunction // Debug only
|
// cppcheck-suppress unusedFunction // Debug only
|
||||||
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE
|
void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE
|
||||||
dumpPtrs(cout); // LCOV_EXCL_LINE
|
dumpPtrs(cout); // LCOV_EXCL_LINE
|
||||||
cout<<" Fileline = "<<fileline()<<endl; // LCOV_EXCL_LINE
|
cout << " Fileline = " << fileline() << endl; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
// cppcheck-suppress unusedFunction // Debug only
|
// cppcheck-suppress unusedFunction // Debug only
|
||||||
void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
|
void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
|
||||||
@@ -1007,7 +1042,8 @@ void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE
|
|||||||
}
|
}
|
||||||
// cppcheck-suppress unusedFunction // Debug only
|
// cppcheck-suppress unusedFunction // Debug only
|
||||||
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE
|
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE
|
||||||
string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
|
string filename
|
||||||
|
= filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE
|
||||||
v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE
|
v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1021,45 +1057,53 @@ void AstNode::checkIter() const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::dumpPtrs(std::ostream& os) const {
|
void AstNode::dumpPtrs(std::ostream& os) const {
|
||||||
os<<"This="<<typeName()<<" "<<cvtToHex(this);
|
os << "This=" << typeName() << " " << cvtToHex(this);
|
||||||
os<<" back="<<cvtToHex(backp());
|
os << " back=" << cvtToHex(backp());
|
||||||
if (nextp()) os<<" next="<<cvtToHex(nextp());
|
if (nextp()) os << " next=" << cvtToHex(nextp());
|
||||||
if (m_headtailp==this) os<<" headtail=this";
|
if (m_headtailp == this) {
|
||||||
else os<<" headtail="<<cvtToHex(m_headtailp);
|
os << " headtail=this";
|
||||||
if (op1p()) os<<" op1p="<<cvtToHex(op1p());
|
} else {
|
||||||
if (op2p()) os<<" op2p="<<cvtToHex(op2p());
|
os << " headtail=" << cvtToHex(m_headtailp);
|
||||||
if (op3p()) os<<" op3p="<<cvtToHex(op3p());
|
|
||||||
if (op4p()) os<<" op4p="<<cvtToHex(op4p());
|
|
||||||
if (user1p()) os<<" user1p="<<cvtToHex(user1p());
|
|
||||||
if (user2p()) os<<" user2p="<<cvtToHex(user2p());
|
|
||||||
if (user3p()) os<<" user3p="<<cvtToHex(user3p());
|
|
||||||
if (user4p()) os<<" user4p="<<cvtToHex(user4p());
|
|
||||||
if (user5p()) os<<" user5p="<<cvtToHex(user5p());
|
|
||||||
if (m_iterpp) {
|
|
||||||
os<<" iterpp="<<cvtToHex(m_iterpp);
|
|
||||||
os<<"*="<<cvtToHex(*m_iterpp);
|
|
||||||
}
|
}
|
||||||
os<<endl;
|
if (op1p()) os << " op1p=" << cvtToHex(op1p());
|
||||||
|
if (op2p()) os << " op2p=" << cvtToHex(op2p());
|
||||||
|
if (op3p()) os << " op3p=" << cvtToHex(op3p());
|
||||||
|
if (op4p()) os << " op4p=" << cvtToHex(op4p());
|
||||||
|
if (user1p()) os << " user1p=" << cvtToHex(user1p());
|
||||||
|
if (user2p()) os << " user2p=" << cvtToHex(user2p());
|
||||||
|
if (user3p()) os << " user3p=" << cvtToHex(user3p());
|
||||||
|
if (user4p()) os << " user4p=" << cvtToHex(user4p());
|
||||||
|
if (user5p()) os << " user5p=" << cvtToHex(user5p());
|
||||||
|
if (m_iterpp) {
|
||||||
|
os << " iterpp=" << cvtToHex(m_iterpp);
|
||||||
|
os << "*=" << cvtToHex(*m_iterpp);
|
||||||
|
}
|
||||||
|
os << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) const {
|
void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) const {
|
||||||
static int s_debugFileline = v3Global.opt.debugSrcLevel("fileline"); // --debugi-fileline 9
|
static int s_debugFileline = v3Global.opt.debugSrcLevel("fileline"); // --debugi-fileline 9
|
||||||
os<<indent<<" "<<this<<endl;
|
os << indent << " " << this << endl;
|
||||||
if (debug()>8) { os<<indent<<" "; dumpPtrs(os); }
|
if (debug() > 8) {
|
||||||
if (s_debugFileline >= 9) {
|
os << indent << " ";
|
||||||
os<<fileline()->warnContextSecondary();
|
dumpPtrs(os);
|
||||||
}
|
}
|
||||||
if (maxDepth==1) {
|
if (s_debugFileline >= 9) { os << fileline()->warnContextSecondary(); }
|
||||||
if (op1p()||op2p()||op3p()||op4p()) { os<<indent<<"1: ...(maxDepth)"<<endl; }
|
if (maxDepth == 1) {
|
||||||
|
if (op1p() || op2p() || op3p() || op4p()) { os << indent << "1: ...(maxDepth)" << endl; }
|
||||||
} else {
|
} else {
|
||||||
for (const AstNode* nodep=op1p(); nodep; nodep=nodep->nextp()) {
|
for (const AstNode* nodep = op1p(); nodep; nodep = nodep->nextp()) {
|
||||||
nodep->dumpTree(os, indent+"1:", maxDepth-1); }
|
nodep->dumpTree(os, indent + "1:", maxDepth - 1);
|
||||||
for (const AstNode* nodep=op2p(); nodep; nodep=nodep->nextp()) {
|
}
|
||||||
nodep->dumpTree(os, indent+"2:", maxDepth-1); }
|
for (const AstNode* nodep = op2p(); nodep; nodep = nodep->nextp()) {
|
||||||
for (const AstNode* nodep=op3p(); nodep; nodep=nodep->nextp()) {
|
nodep->dumpTree(os, indent + "2:", maxDepth - 1);
|
||||||
nodep->dumpTree(os, indent+"3:", maxDepth-1); }
|
}
|
||||||
for (const AstNode* nodep=op4p(); nodep; nodep=nodep->nextp()) {
|
for (const AstNode* nodep = op3p(); nodep; nodep = nodep->nextp()) {
|
||||||
nodep->dumpTree(os, indent+"4:", maxDepth-1); }
|
nodep->dumpTree(os, indent + "3:", maxDepth - 1);
|
||||||
|
}
|
||||||
|
for (const AstNode* nodep = op4p(); nodep; nodep = nodep->nextp()) {
|
||||||
|
nodep->dumpTree(os, indent + "4:", maxDepth - 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1073,18 +1117,18 @@ void AstNode::dumpTreeAndNext(std::ostream& os, const string& indent, int maxDep
|
|||||||
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
||||||
// Not const function as calls checkTree
|
// Not const function as calls checkTree
|
||||||
if (doDump) {
|
if (doDump) {
|
||||||
{ // Write log & close
|
{ // Write log & close
|
||||||
UINFO(2,"Dumping "<<filename<<endl);
|
UINFO(2, "Dumping " << filename << endl);
|
||||||
const vl_unique_ptr<std::ofstream> logsp (V3File::new_ofstream(filename, append));
|
const vl_unique_ptr<std::ofstream> logsp(V3File::new_ofstream(filename, append));
|
||||||
if (logsp->fail()) v3fatal("Can't write "<<filename);
|
if (logsp->fail()) v3fatal("Can't write " << filename);
|
||||||
*logsp<<"Verilator Tree Dump (format 0x3900) from <e"<<std::dec<<editCountLast()<<">";
|
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
|
||||||
*logsp<<" to <e"<<std::dec<<editCountGbl()<<">"<<endl;
|
*logsp << "> to <e" << std::dec << editCountGbl() << ">" << endl;
|
||||||
if (editCountGbl()==editCountLast()
|
if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) {
|
||||||
&& !(v3Global.opt.dumpTree()>=9)) {
|
*logsp << endl;
|
||||||
*logsp<<endl;
|
*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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1095,12 +1139,12 @@ 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); assert(0); VL_UNREACHABLE
|
v3errorEnd(str);
|
||||||
|
assert(0); // LCOV_EXCL_LINE
|
||||||
|
VL_UNREACHABLE
|
||||||
}
|
}
|
||||||
|
|
||||||
string AstNode::locationStr() const {
|
string AstNode::locationStr() const {
|
||||||
@@ -1108,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))) {
|
||||||
@@ -1148,12 +1192,12 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
|
|||||||
V3Error::v3errorEnd(str, locationStr());
|
V3Error::v3errorEnd(str, locationStr());
|
||||||
} else {
|
} else {
|
||||||
std::ostringstream nsstr;
|
std::ostringstream nsstr;
|
||||||
nsstr<<str.str();
|
nsstr << str.str();
|
||||||
if (debug()) {
|
if (debug()) {
|
||||||
nsstr<<endl;
|
nsstr << endl;
|
||||||
nsstr<<"-node: ";
|
nsstr << "-node: ";
|
||||||
const_cast<AstNode*>(this)->dump(nsstr);
|
const_cast<AstNode*>(this)->dump(nsstr);
|
||||||
nsstr<<endl;
|
nsstr << endl;
|
||||||
}
|
}
|
||||||
m_fileline->v3errorEnd(nsstr, locationStr());
|
m_fileline->v3errorEnd(nsstr, locationStr());
|
||||||
}
|
}
|
||||||
@@ -1164,8 +1208,7 @@ void AstNode::v3errorEnd(std::ostringstream& str) const {
|
|||||||
|
|
||||||
void AstNode::dtypeChgSigned(bool flag) {
|
void AstNode::dtypeChgSigned(bool flag) {
|
||||||
UASSERT_OBJ(dtypep(), this, "No dtype when changing to (un)signed");
|
UASSERT_OBJ(dtypep(), this, "No dtype when changing to (un)signed");
|
||||||
dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(),
|
dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(), VSigning::fromBool(flag));
|
||||||
AstNumeric::fromBool(flag));
|
|
||||||
}
|
}
|
||||||
void AstNode::dtypeChgWidth(int width, int widthMin) {
|
void AstNode::dtypeChgWidth(int width, int widthMin) {
|
||||||
UASSERT_OBJ(dtypep(), this,
|
UASSERT_OBJ(dtypep(), this,
|
||||||
@@ -1173,14 +1216,14 @@ void AstNode::dtypeChgWidth(int width, int widthMin) {
|
|||||||
dtypeChgWidthSigned(width, widthMin, dtypep()->numeric());
|
dtypeChgWidthSigned(width, widthMin, dtypep()->numeric());
|
||||||
}
|
}
|
||||||
|
|
||||||
void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) {
|
void AstNode::dtypeChgWidthSigned(int width, int widthMin, VSigning numeric) {
|
||||||
if (!dtypep()) {
|
if (!dtypep()) {
|
||||||
// We allow dtypep() to be null, as before/during widthing dtypes are not resolved
|
// We allow dtypep() to be null, as before/during widthing dtypes are not resolved
|
||||||
dtypeSetLogicUnsized(width, widthMin, numeric);
|
dtypeSetLogicUnsized(width, widthMin, numeric);
|
||||||
} else {
|
} else {
|
||||||
if (width==dtypep()->width()
|
if (width == dtypep()->width() && widthMin == dtypep()->widthMin()
|
||||||
&& widthMin==dtypep()->widthMin()
|
&& numeric == dtypep()->numeric())
|
||||||
&& numeric==dtypep()->numeric()) return; // Correct already
|
return; // Correct already
|
||||||
// FUTURE: We may be pointing at a two state data type, and this may
|
// FUTURE: We may be pointing at a two state data type, and this may
|
||||||
// convert it to logic. Since the AstVar remains correct, we
|
// convert it to logic. Since the AstVar remains correct, we
|
||||||
// work OK but this assumption may break in the future.
|
// work OK but this assumption may break in the future.
|
||||||
@@ -1193,29 +1236,31 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) {
|
|||||||
AstNodeDType* AstNode::findBasicDType(AstBasicDTypeKwd kwd) const {
|
AstNodeDType* AstNode::findBasicDType(AstBasicDTypeKwd kwd) const {
|
||||||
// For 'simple' types we use the global directory. These are all unsized.
|
// For 'simple' types we use the global directory. These are all unsized.
|
||||||
// More advanced types land under the module/task/etc
|
// More advanced types land under the module/task/etc
|
||||||
return v3Global.rootp()->typeTablep()
|
return v3Global.rootp()->typeTablep()->findBasicDType(fileline(), kwd);
|
||||||
->findBasicDType(fileline(), kwd);
|
|
||||||
}
|
}
|
||||||
AstNodeDType* AstNode::findBitDType(int width, int widthMin, AstNumeric numeric) const {
|
AstNodeDType* AstNode::findBitDType(int width, int widthMin, VSigning numeric) const {
|
||||||
return v3Global.rootp()->typeTablep()
|
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT,
|
||||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, width, widthMin, numeric);
|
width, widthMin, numeric);
|
||||||
}
|
}
|
||||||
AstNodeDType* AstNode::findLogicDType(int width, int widthMin, AstNumeric numeric) const {
|
AstNodeDType* AstNode::findLogicDType(int width, int widthMin, VSigning numeric) const {
|
||||||
return v3Global.rootp()->typeTablep()
|
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC,
|
||||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, width, widthMin, numeric);
|
width, widthMin, numeric);
|
||||||
}
|
}
|
||||||
AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin,
|
AstNodeDType* AstNode::findLogicRangeDType(const VNumRange& range, int widthMin,
|
||||||
AstNumeric numeric) const {
|
VSigning numeric) const {
|
||||||
return v3Global.rootp()->typeTablep()
|
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC,
|
||||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, range, widthMin, numeric);
|
range, widthMin, numeric);
|
||||||
|
}
|
||||||
|
AstNodeDType* AstNode::findBitRangeDType(const VNumRange& range, int widthMin,
|
||||||
|
VSigning numeric) const {
|
||||||
|
return v3Global.rootp()->typeTablep()->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT,
|
||||||
|
range, widthMin, numeric);
|
||||||
}
|
}
|
||||||
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
|
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
|
||||||
return v3Global.rootp()->typeTablep()
|
return v3Global.rootp()->typeTablep()->findInsertSameDType(nodep);
|
||||||
->findInsertSameDType(nodep);
|
|
||||||
}
|
}
|
||||||
AstNodeDType* AstNode::findVoidDType() const {
|
AstNodeDType* AstNode::findVoidDType() const {
|
||||||
return v3Global.rootp()->typeTablep()
|
return v3Global.rootp()->typeTablep()->findVoidDType(fileline());
|
||||||
->findVoidDType(fileline());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|||||||
+1117
-709
File diff suppressed because it is too large
Load Diff
@@ -18,12 +18,12 @@
|
|||||||
#define _V3ASTCONSTONLY_H_ 1
|
#define _V3ASTCONSTONLY_H_ 1
|
||||||
|
|
||||||
// Include only in visitors that do not not edit nodes, so should use constant iterators
|
// Include only in visitors that do not not edit nodes, so should use constant iterators
|
||||||
#define iterateAndNext error_use_iterateAndNextConst
|
#define iterateAndNext error_use_iterateAndNextConst
|
||||||
#define iterateChildren error_use_iterateChildrenConst
|
#define iterateChildren error_use_iterateChildrenConst
|
||||||
|
|
||||||
#define addNext error_no_addNext_in_ConstOnlyVisitor
|
#define addNext error_no_addNext_in_ConstOnlyVisitor
|
||||||
#define replaceWith error_no_replaceWith_in_ConstOnlyVisitor
|
#define replaceWith error_no_replaceWith_in_ConstOnlyVisitor
|
||||||
#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor
|
#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor
|
||||||
#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor
|
#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor
|
||||||
|
|
||||||
#endif // Guard
|
#endif // Guard
|
||||||
|
|||||||
+677
-482
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user