mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 16:44:11 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d6ba65ba75 | ||
|
|
f496138855 | ||
|
|
2f272a4190 | ||
|
|
469eca7de2 | ||
|
|
ec2eae607a | ||
|
|
292c2e289e | ||
|
|
87ac61140d | ||
|
|
81ee89de15 | ||
|
|
83081aaefc | ||
|
|
fd2917c928 | ||
|
|
4cd69f9feb | ||
|
|
4e5c7f4568 | ||
|
|
647af27274 | ||
|
|
8cc7e180ca | ||
|
|
d3d45c0be5 | ||
|
|
549dd31224 | ||
|
|
36888fac5d | ||
|
|
2409f32d87 | ||
|
|
8c3cc3af8f | ||
|
|
76fe224e7c | ||
|
|
7ccc93d9df | ||
|
|
55661e7f71 | ||
|
|
ece0613e09 | ||
|
|
0dce97b09d | ||
|
|
a3d0cc6522 | ||
|
|
1df20f7076 | ||
|
|
2fc94557a0 | ||
|
|
789698cb5c | ||
|
|
3cced9baad | ||
|
|
f3cc32554c | ||
|
|
2a905c1d6e | ||
|
|
230b145c04 | ||
|
|
9f34764f4b | ||
|
|
69ac3c14e8 | ||
|
|
f98637e122 | ||
|
|
6d936654ba | ||
|
|
4dd4047c47 | ||
|
|
1710b6bab4 | ||
|
|
041f6603c3 | ||
|
|
5acced1e33 | ||
|
|
920c8012de | ||
|
|
8f1ea09558 | ||
|
|
b873c23cf2 | ||
|
|
13c7b6e827 | ||
|
|
bbce7926b9 | ||
|
|
2c445e4bfd | ||
|
|
338d54fd34 | ||
|
|
009d1f2f5b | ||
|
|
08279645ca | ||
|
|
28ecd8e908 | ||
|
|
bc8a332ee8 | ||
|
|
d52822781c | ||
|
|
bdd37e40fe | ||
|
|
4b713e9882 | ||
|
|
fd9f5ab34e | ||
|
|
d06f986b51 | ||
|
|
8638e46cb7 | ||
|
|
85909f02b3 | ||
|
|
3572bd2f1a | ||
|
|
ff1d20d50c | ||
|
|
c300075a20 | ||
|
|
4bdfc653a3 | ||
|
|
554653900a | ||
|
|
b90b81e12c | ||
|
|
bf2b4e1b6a | ||
|
|
c05c48aaf3 | ||
|
|
39143cc15a | ||
|
|
03012da11c | ||
|
|
0547108e3f | ||
|
|
1a31aa5d62 | ||
|
|
13a1240359 | ||
|
|
b7e5486baa | ||
|
|
afeca21d73 | ||
|
|
d0ec6092b3 | ||
|
|
5c923d6629 | ||
|
|
1dc6fd3d93 | ||
|
|
5b56c80830 | ||
|
|
2291d3d4c6 | ||
|
|
02e7767886 | ||
|
|
2a01365f9b | ||
|
|
91c8866ac3 | ||
|
|
798bbe98e8 | ||
|
|
a3bbf13506 | ||
|
|
650da7beb2 | ||
|
|
3bc09d49fb | ||
|
|
6c61a9aff3 | ||
|
|
a4085f3a06 | ||
|
|
3ae18af8dd | ||
|
|
811eab8fa5 | ||
|
|
4ec75b2618 | ||
|
|
5a65d27851 | ||
|
|
685ea0bc65 | ||
|
|
c48d80592e | ||
|
|
0aa8356eca | ||
|
|
670b7c5243 | ||
|
|
706679e6b1 | ||
|
|
d288488b7f | ||
|
|
b17619296a | ||
|
|
88bd479bc7 | ||
|
|
2584befa5a | ||
|
|
90215878f8 | ||
|
|
a1a74cb1d9 | ||
|
|
9f9770e722 | ||
|
|
888af29a72 | ||
|
|
5f39c69d19 | ||
|
|
e7de2c5a05 | ||
|
|
59b07529b1 | ||
|
|
a6e9bce0dd | ||
|
|
2c52119d6c | ||
|
|
48faf8d036 | ||
|
|
0484143282 | ||
|
|
0ee214a157 | ||
|
|
774ec42be4 | ||
|
|
5a6f2b661d | ||
|
|
80cba789f4 | ||
|
|
92dd8ee8f5 | ||
|
|
1665d15d4d | ||
|
|
f0fb0b05ff | ||
|
|
02e88e3848 | ||
|
|
87eef36b1c | ||
|
|
579257bc42 | ||
|
|
e2041f7450 | ||
|
|
70112438c3 | ||
|
|
175e1dde73 | ||
|
|
e990415ee0 | ||
|
|
1543b202b2 | ||
|
|
f63168a5b5 | ||
|
|
49bccb5f1b | ||
|
|
c7e1358bb7 | ||
|
|
62a58f420c | ||
|
|
dd95e033e7 | ||
|
|
371a4055b0 | ||
|
|
f251f7b774 | ||
|
|
0f3e0de891 | ||
|
|
7081ea0ede | ||
|
|
fb04765c0e | ||
|
|
b8bda729d4 | ||
|
|
195a665293 | ||
|
|
c8de3630a5 | ||
|
|
99a29acca0 | ||
|
|
48a607cc78 | ||
|
|
19170badd3 | ||
|
|
77fc771ed0 | ||
|
|
9b9a554489 | ||
|
|
0fe8c73d19 | ||
|
|
eb66e137db | ||
|
|
c2b82c293f | ||
|
|
0b7510befa | ||
|
|
140eb0a6e5 | ||
|
|
6b8f253ecd | ||
|
|
ac29393ec9 | ||
|
|
22d6bb8180 | ||
|
|
f4e4602dcb | ||
|
|
521c5c2f75 | ||
|
|
3525484730 | ||
|
|
4a58997604 | ||
|
|
ef259f63ca | ||
|
|
2f690c0530 | ||
|
|
283a5edbdb | ||
|
|
e566b5a4f5 | ||
|
|
4e4fdd3b66 | ||
|
|
434896d50c | ||
|
|
1e7611edea | ||
|
|
2890126110 | ||
|
|
07bb8c701d | ||
|
|
55ae48ac13 | ||
|
|
c83ee391bb | ||
|
|
d01b917062 | ||
|
|
b21117091b | ||
|
|
3a73d83741 | ||
|
|
9643232d36 | ||
|
|
7b41d2046d | ||
|
|
7eb1b6c32b | ||
|
|
083fb7e9c2 | ||
|
|
afb8428db4 | ||
|
|
d6923c8571 | ||
|
|
1c38744fd1 | ||
|
|
51691dfde5 | ||
|
|
409efa1249 | ||
|
|
e4ff0909dc | ||
|
|
d3670b6890 | ||
|
|
7a74ddc1af | ||
|
|
551862a55e | ||
|
|
d3fcec3e84 | ||
|
|
088862d449 | ||
|
|
e9f758ce67 | ||
|
|
b698bfd850 | ||
|
|
c9970ff822 | ||
|
|
df594ee430 | ||
|
|
201e343795 | ||
|
|
9a307c4abd | ||
|
|
657d7f257b | ||
|
|
0ec5e02ce1 | ||
|
|
cdfb2221bb | ||
|
|
f133a2811f | ||
|
|
aecf38e3ad | ||
|
|
fa32d10f39 | ||
|
|
f4fe89a8c4 | ||
|
|
675d9a641e | ||
|
|
d896f1ff08 | ||
|
|
5cb6f370e9 | ||
|
|
e04ef5d83a | ||
|
|
155dcc5658 | ||
|
|
e927536099 | ||
|
|
f623db7d68 | ||
|
|
d40f7f5167 | ||
|
|
34bb013941 | ||
|
|
ae35be9102 | ||
|
|
bde4097df2 | ||
|
|
17b70788df | ||
|
|
b1927e4fb5 | ||
|
|
c4cb26fa9a | ||
|
|
4e86e60491 | ||
|
|
d3e07b6ad9 | ||
|
|
fa4af38b0a | ||
|
|
a9635aaa2c | ||
|
|
f0cd6dd95c | ||
|
|
d8fdfa6be2 | ||
|
|
f9511e9755 | ||
|
|
cfe1f23fff | ||
|
|
8741fd17ad | ||
|
|
ffe76717c6 | ||
|
|
eb8bbcda05 | ||
|
|
ed7040adc0 | ||
|
|
48776277bd | ||
|
|
8ca45df9c7 | ||
|
|
8db9c1d227 | ||
|
|
930f35acc9 | ||
|
|
13e0fc7c27 | ||
|
|
a730daabef | ||
|
|
3c28b72897 | ||
|
|
05e5f1955e | ||
|
|
378800ee4a | ||
|
|
43a57da950 | ||
|
|
99a43b7695 | ||
|
|
59d2eea302 | ||
|
|
6f3f64e63f | ||
|
|
48c71ef76c | ||
|
|
563faeb33f | ||
|
|
9c5c77c69c | ||
|
|
4573e04488 | ||
|
|
6cb0a41857 | ||
|
|
124e3463fc | ||
|
|
1b15509a9c | ||
|
|
eb3f10399a | ||
|
|
4660806c8f | ||
|
|
6f5d1037b4 | ||
|
|
24b097b228 | ||
|
|
a0ea96b355 | ||
|
|
a663da7393 | ||
|
|
c812a9b18f | ||
|
|
367249ec84 | ||
|
|
f4acc59b82 | ||
|
|
d1da1664f0 | ||
|
|
b100615726 | ||
|
|
ec0815e9ac | ||
|
|
97e9996f0b | ||
|
|
b7af859ba3 | ||
|
|
701fa5438a | ||
|
|
004865a8b2 | ||
|
|
3e5859e5da | ||
|
|
78555b683c | ||
|
|
c2e44dbd99 | ||
|
|
18fc3e6089 | ||
|
|
f4f8ea0dcf | ||
|
|
f78c4e8490 | ||
|
|
e6fe367bdb | ||
|
|
3426ee5170 | ||
|
|
a32b8d80f9 | ||
|
|
3b81654c72 | ||
|
|
6abd556f5a | ||
|
|
31c1df638b | ||
|
|
f4cb2c8cf2 | ||
|
|
7d5e19365e | ||
|
|
6fa1ade4e0 | ||
|
|
99c619a4c9 | ||
|
|
37a4002098 | ||
|
|
45ee949cc4 | ||
|
|
54f9f4b6a9 | ||
|
|
a61178bd89 | ||
|
|
2f5c58b345 | ||
|
|
403a197e23 | ||
|
|
3a659d460d | ||
|
|
8707c88787 | ||
|
|
167cba723e | ||
|
|
7f40dd8b5b | ||
|
|
1609c23fea | ||
|
|
216fc8a212 | ||
|
|
5136ea1082 | ||
|
|
5b931faf2b | ||
|
|
a2496e041e | ||
|
|
fab268f772 | ||
|
|
550d47b7f4 | ||
|
|
a01a21db86 | ||
|
|
2082f1aa9e | ||
|
|
50a5a1ff5b | ||
|
|
1600cc01a4 | ||
|
|
b9e1d55262 | ||
|
|
0d43c14b93 | ||
|
|
87d1c10fa7 | ||
|
|
a2506a6f96 | ||
|
|
20dba7464d | ||
|
|
cb5d03ff0b | ||
|
|
2727c33219 | ||
|
|
0419ed0430 | ||
|
|
1e3c7a5496 | ||
|
|
d2dfcbca53 | ||
|
|
e779934443 | ||
|
|
a3b255b054 | ||
|
|
f5caa4b7dc | ||
|
|
8f4490628f | ||
|
|
df566bdf4d | ||
|
|
981d3ce782 | ||
|
|
b7345eb5d5 | ||
|
|
2bd2b9324f | ||
|
|
298faa84ee | ||
|
|
43377ed8b0 | ||
|
|
b18037b7e7 | ||
|
|
095b1ccb67 | ||
|
|
2a30a87580 | ||
|
|
e11bc6beeb | ||
|
|
0a9b31bb30 | ||
|
|
34e37d7bd0 | ||
|
|
164a7a7c5d | ||
|
|
67ea819d82 | ||
|
|
60f9e21d8c | ||
|
|
dc037db1cd | ||
|
|
0658af90f5 | ||
|
|
131623de34 | ||
|
|
74ae879c2f | ||
|
|
8c3b754bac | ||
|
|
e080f5c0cb | ||
|
|
2284cf595d | ||
|
|
b1cc0c54c1 | ||
|
|
4cf017d7fe | ||
|
|
25f5db4b5f | ||
|
|
3cf9606ea9 | ||
|
|
6882f8c55e | ||
|
|
2696a9a5bd | ||
|
|
abb46c9cb2 | ||
|
|
bbb223f217 | ||
|
|
570e1bc35a | ||
|
|
11da07d3b9 | ||
|
|
2cfec0ecc3 | ||
|
|
e3e7b3f2b5 | ||
|
|
fe0b210a0c | ||
|
|
c383f4868f | ||
|
|
b66fdd7421 | ||
|
|
83878325a7 | ||
|
|
490bc63eb5 | ||
|
|
947b6fd23f | ||
|
|
de44ca8df3 | ||
|
|
3cee54dfdf | ||
|
|
dace2c0a9a | ||
|
|
ca4858eb7f | ||
|
|
a6d438d111 | ||
|
|
955ed3f193 | ||
|
|
8bffb8c391 | ||
|
|
85356f464f | ||
|
|
72993ec3dd | ||
|
|
d6a294b784 | ||
|
|
864a852bca | ||
|
|
b0992406aa | ||
|
|
9e2c8aefc8 | ||
|
|
4c584c17e6 | ||
|
|
3315a6e431 | ||
|
|
ba0183131c | ||
|
|
e1580b9c3d | ||
|
|
aadd5ea509 | ||
|
|
833df6d9ea | ||
|
|
607c19a67d | ||
|
|
d5cfe1a379 | ||
|
|
6e557791c8 |
+1
-1
@@ -1,4 +1,4 @@
|
||||
Checks: '*,-hicpp*,-android-cloexec-fopen,-cert-dcl50-cpp,-cert-env33-c,-cert-err34-c,-cert-err58-cpp,-clang-analyzer-core.UndefinedBinaryOperatorResult,-clang-analyzer-security*,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-*,-google-default-arguments,-google-readability-todo,-google-runtime-references,-llvm-header-guard,-llvm-include-order,-misc-string-integer-assignment,-misc-string-literal-with-embedded-nul,-modernize-use-auto,-modernize-use-trailing-return-type,-readability-braces-around-statements,-readability-container-size-empty,-readability-delete-null-pointer,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-static-accessed-through-instance'
|
||||
Checks: '*,-hicpp*,-android-cloexec-fopen,-cert-dcl50-cpp,-cert-env33-c,-cert-err34-c,-cert-err58-cpp,-clang-analyzer-core.UndefinedBinaryOperatorResult,-clang-analyzer-security*,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-*,-google-default-arguments,-google-readability-todo,-google-runtime-references,-llvm-header-guard,-llvm-include-order,-misc-string-integer-assignment,-misc-string-literal-with-embedded-nul,-modernize-use-auto,-modernize-use-trailing-return-type,-readability-braces-around-statements,-readability-container-size-empty,-readability-delete-null-pointer,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-static-accessed-through-instance,-llvmlibc-*,-altera-*'
|
||||
WarningsAsErrors: ''
|
||||
HeaderFilterRegex: ''
|
||||
FormatStyle: none
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
---
|
||||
exclude_paths:
|
||||
- '.github/**'
|
||||
- 'ci/build_verilator.sh'
|
||||
- 'include/vltstd/**'
|
||||
- 'nodist/fastcov.py'
|
||||
- ".github/**"
|
||||
- "ci/build_verilator.sh"
|
||||
- "include/vltstd/**"
|
||||
- "nodist/fastcov.py"
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "Verilator Build Environment",
|
||||
"name": "Verilator Build Environment",
|
||||
|
||||
"build": {
|
||||
"build": {
|
||||
"dockerfile": "../ci/docker/buildenv/Dockerfile"
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ Thanks for taking the time to report this.
|
||||
|
||||
What would you like added/supported?
|
||||
|
||||
What 'verilator --version' are you using? Did you try it with the git master version?
|
||||
|
||||
Can you attach an example that runs on other simulators? (Must be openly licensed, ideally in test_regress format.)
|
||||
|
||||
May we assist you in trying to fix this in Verilator yourself?
|
||||
|
||||
@@ -8,3 +8,5 @@ assignees: ''
|
||||
---
|
||||
|
||||
How may we help - what is your question?
|
||||
|
||||
(If reporting a bug or requesting a feature please use one of the other issue templates.)
|
||||
|
||||
+84
-84
@@ -1,3 +1,4 @@
|
||||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# This name is key to badges in README.rst, so we use the name build
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
@@ -9,7 +10,7 @@ on:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
@@ -35,14 +36,14 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
os: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04]
|
||||
compiler:
|
||||
- { cc: clang, cxx: clang++ }
|
||||
- { cc: gcc, cxx: g++ }
|
||||
- {cc: clang, cxx: clang++}
|
||||
- {cc: gcc, cxx: g++}
|
||||
include:
|
||||
# Build GCC 10 on ubuntu-20.04
|
||||
- os: ubuntu-20.04
|
||||
compiler: { cc: gcc-10, cxx: g++-10 }
|
||||
compiler: {cc: gcc-10, cxx: g++-10}
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }}
|
||||
env:
|
||||
@@ -51,41 +52,40 @@ jobs:
|
||||
CC: ${{ matrix.compiler.cc }}
|
||||
CXX: ${{ matrix.compiler.cxx }}
|
||||
CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}
|
||||
CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
|
||||
CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total)
|
||||
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
- name: Build
|
||||
run: ./ci/ci-script.bash
|
||||
- name: Build
|
||||
run: ./ci/ci-script.bash
|
||||
|
||||
- name: Tar up repository
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
- name: Tar up repository
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
test:
|
||||
needs: build
|
||||
@@ -94,25 +94,25 @@ jobs:
|
||||
matrix:
|
||||
os: [ubuntu-22.04, ubuntu-20.04]
|
||||
compiler:
|
||||
- { cc: clang, cxx: clang++ }
|
||||
- { cc: gcc, cxx: g++ }
|
||||
- {cc: clang, cxx: clang++}
|
||||
- {cc: gcc, cxx: g++}
|
||||
reloc: [0]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1]
|
||||
include:
|
||||
# Test with GCC 10 on ubuntu-20.04
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-0}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-1}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-2}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-3}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-0}
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-1}
|
||||
# Test relocated installation - on most common platform only
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-0}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-1}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-2}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-3}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: vltmt-0}
|
||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: vltmt-1}
|
||||
# Test with GCC 10 on ubuntu-20.04, also test relocation
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: dist-vlt-0}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: dist-vlt-1}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: dist-vlt-2}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: dist-vlt-3}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: vltmt-0}
|
||||
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: vltmt-1}
|
||||
# Ubuntu 24.04 only on GCC; not passing on clang yet
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-0}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-1}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-2}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-3}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: vltmt-0}
|
||||
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: vltmt-1}
|
||||
runs-on: ${{ matrix.os }}
|
||||
name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
||||
env:
|
||||
@@ -122,37 +122,37 @@ jobs:
|
||||
CC: ${{ matrix.compiler.cc }}
|
||||
CXX: ${{ matrix.compiler.cxx }}
|
||||
CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.reloc }}-${{ matrix.suite }}
|
||||
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
|
||||
CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total)
|
||||
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
|
||||
steps:
|
||||
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
|
||||
- name: Unpack tar archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
- name: Unpack tar archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||
restore-keys: |
|
||||
${{ env.CACHE_KEY }}-
|
||||
|
||||
- name: Install test dependencies
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install test dependencies
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
TESTS: ${{ matrix.suite }}
|
||||
run: ./ci/ci-script.bash
|
||||
- name: Test
|
||||
env:
|
||||
TESTS: ${{ matrix.suite }}
|
||||
run: ./ci/ci-script.bash
|
||||
|
||||
lint-py:
|
||||
runs-on: ubuntu-22.04
|
||||
@@ -161,21 +161,21 @@ jobs:
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
# We use specific version numbers, otherwise a Python package
|
||||
# update may add a warning and break our build
|
||||
- name: Install packages for lint
|
||||
run: sudo pip3 install pylint==3.0.2 ruff==0.1.3 clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||
- name: Install packages for lint
|
||||
run: sudo pip3 install pylint==3.0.2 ruff==0.1.3 clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||
|
||||
- name: Configure
|
||||
run: autoconf && ./configure --enable-longtests --enable-ccwarn
|
||||
- name: Configure
|
||||
run: autoconf && ./configure --enable-longtests --enable-ccwarn
|
||||
|
||||
- name: Lint
|
||||
run: make -k lint-py
|
||||
- name: Lint
|
||||
run: make -k lint-py
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
#
|
||||
name: Contributor Agreement
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
Test:
|
||||
name: "'docs/CONTRIBUTORS' was signed"
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- run: test_regress/t/t_dist_contributors.pl
|
||||
- uses: actions/checkout@v4
|
||||
- run: test_regress/t/t_dist_contributors.py
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
@@ -6,7 +7,7 @@ name: coverage
|
||||
on:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
@@ -21,7 +22,6 @@ defaults:
|
||||
|
||||
jobs:
|
||||
|
||||
|
||||
Build:
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
@@ -29,49 +29,36 @@ jobs:
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install packages for build
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
- name: Build
|
||||
run: ./ci/ci-script.bash
|
||||
- name: Build
|
||||
run: ./ci/ci-script.bash
|
||||
|
||||
- name: Tar up repository
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
- name: Tar up repository
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
Test:
|
||||
needs: Build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
test:
|
||||
- vlt-
|
||||
- vltmt-
|
||||
num:
|
||||
- 0
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- 4
|
||||
- 5
|
||||
- 6
|
||||
- 7
|
||||
- 8
|
||||
- 9
|
||||
test: [vlt-, vltmt-]
|
||||
num: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
include:
|
||||
- { test: dist, num: '' }
|
||||
- {test: dist, num: ''}
|
||||
runs-on: ubuntu-22.04
|
||||
name: test-${{ matrix.test }}${{ matrix.num }}
|
||||
env:
|
||||
@@ -79,20 +66,27 @@ jobs:
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
|
||||
- name: Unpack tar archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
- name: Unpack tar archive
|
||||
working-directory: ${{ github.workspace }}
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
- name: Install test dependencies
|
||||
run: ./ci/ci-install.bash
|
||||
- name: Install test dependencies
|
||||
run: ./ci/ci-install.bash
|
||||
|
||||
- name: Test
|
||||
env:
|
||||
TESTS: coverage-${{ matrix.test }}${{ matrix.num }}
|
||||
run: ./ci/ci-script.bash
|
||||
- name: Test
|
||||
env:
|
||||
TESTS: coverage-${{ matrix.test }}${{ matrix.num }}
|
||||
run: ./ci/ci-script.bash
|
||||
|
||||
- name: Upload coverage data to Codecov
|
||||
env:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
run: |
|
||||
find . -name '*.gcno' -exec rm {} \;
|
||||
./ci/codecov -v upload-process -Z --sha ${{ github.sha }} -f nodist/obj_dir/coverage/app_total.info
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
---
|
||||
# Build and push verilator docker image when tags are pushed to the repository.
|
||||
# The following variable(s) must be configured in the github repository:
|
||||
# DOCKER_HUB_NAMESPACE: docker hub namespace.
|
||||
@@ -8,7 +9,7 @@ name: Build Verilator Container
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: [ 'v*' ]
|
||||
tags: ['v*']
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
manual_tag:
|
||||
@@ -34,52 +35,52 @@ jobs:
|
||||
# - "ci/docker/buildenv:verilator-buildenv"
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Extract context variables
|
||||
run: |
|
||||
echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV"
|
||||
echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV"
|
||||
echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV"
|
||||
- name: Extract context variables
|
||||
run: |
|
||||
echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV"
|
||||
echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV"
|
||||
echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Use manual tag
|
||||
if: ${{ inputs.manual_tag }}
|
||||
run: |
|
||||
echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV"
|
||||
- name: Use manual tag
|
||||
if: ${{ inputs.manual_tag }}
|
||||
run: |
|
||||
echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Docker meta
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
||||
tags: |
|
||||
type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
type=raw,value=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }}
|
||||
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
||||
- name: Docker meta
|
||||
id: docker_meta
|
||||
uses: docker/metadata-action@v4
|
||||
with:
|
||||
images: |
|
||||
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
||||
tags: |
|
||||
type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
||||
type=raw,value=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }}
|
||||
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
with:
|
||||
buildkitd-flags: --debug
|
||||
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
- name: Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||
|
||||
- name: Build and Push to Docker
|
||||
uses: docker/build-push-action@v4
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
with:
|
||||
context: ${{ env.build_context }}
|
||||
build-args: SOURCE_COMMIT=${{ env.git_tag }}
|
||||
platforms: linux/arm64,linux/amd64
|
||||
push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }}
|
||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||
- name: Build and Push to Docker
|
||||
uses: docker/build-push-action@v4
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
with:
|
||||
context: ${{ env.build_context }}
|
||||
build-args: SOURCE_COMMIT=${{ env.git_tag }}
|
||||
platforms: linux/arm64,linux/amd64
|
||||
push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }}
|
||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
#
|
||||
name: format
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request_target:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-22.04
|
||||
|
||||
@@ -1,55 +1,50 @@
|
||||
---
|
||||
# DESCRIPTION: Github actions config
|
||||
# This name is key to badges in README.rst, so we use the name build
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
#
|
||||
name: msbuild
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
workflow_dispatch:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0' # weekly
|
||||
|
||||
- cron: 0 0 * * 0 # weekly
|
||||
env:
|
||||
CI_OS_NAME: win
|
||||
CI_COMMIT: ${{ github.sha }}
|
||||
CCACHE_COMPRESS: 1
|
||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||
|
||||
defaults:
|
||||
run:
|
||||
working-directory: repo
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
|
||||
windows:
|
||||
windows:
|
||||
name: run on windows
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: msbuild-msvc-cmake
|
||||
- name: compile
|
||||
env:
|
||||
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
||||
run: ./ci/ci-win-compile.ps1
|
||||
- name: test build
|
||||
run: ./ci/ci-win-test.ps1
|
||||
- name: Zip up repository
|
||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
||||
- name: Upload zip archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/verilator.zip
|
||||
name: verilator-win.zip
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
path: repo
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.CCACHE_DIR }}
|
||||
key: msbuild-msvc-cmake
|
||||
- name: compile
|
||||
env:
|
||||
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
||||
run: ./ci/ci-win-compile.ps1
|
||||
- name: test build
|
||||
run: ./ci/ci-win-test.ps1
|
||||
- name: Zip up repository
|
||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
||||
- name: Upload zip archive
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: ${{ github.workspace }}/repo/verilator.zip
|
||||
name: verilator-win.zip
|
||||
|
||||
+8
-4
@@ -29,14 +29,15 @@ dddrun*
|
||||
doxygen-doc
|
||||
gdbrun*
|
||||
gmon.out
|
||||
ncverilog.history
|
||||
internals.txt
|
||||
ncverilog.history
|
||||
nohup.out
|
||||
verilator-config-version.cmake
|
||||
verilator-config.cmake
|
||||
verilator.pc
|
||||
verilator.txt
|
||||
verilator_bin*
|
||||
verilator_coverage_bin*
|
||||
verilator.pc
|
||||
verilator-config.cmake
|
||||
verilator-config-version.cmake
|
||||
**/__pycache__/*
|
||||
**/_build/*
|
||||
**/obj_dir/*
|
||||
@@ -46,3 +47,6 @@ verilator-config-version.cmake
|
||||
/test_regress/snapshot/
|
||||
xmverilog.*
|
||||
xrun.history
|
||||
|
||||
# Normal CMake build directory
|
||||
/build
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
- id: verilator
|
||||
name: verilator-lint
|
||||
description: Runs verilator Docker image to lint (System) Verilog designs
|
||||
args: [--lint-only]
|
||||
language: docker_image
|
||||
entry: verilator/verilator:latest
|
||||
types_or: [verilog, system-verilog]
|
||||
@@ -0,0 +1,4 @@
|
||||
[style]
|
||||
based_on_style = pep8
|
||||
column_limit = 99
|
||||
#split_before_arithmetic_operator=True
|
||||
+74
-34
@@ -14,36 +14,44 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
||||
project(Verilator
|
||||
VERSION 5.026
|
||||
project(
|
||||
Verilator
|
||||
VERSION 5.030
|
||||
HOMEPAGE_URL https://verilator.org
|
||||
LANGUAGES CXX
|
||||
)
|
||||
|
||||
option(DEBUG_AND_RELEASE_AND_COVERAGE
|
||||
"Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild.")
|
||||
option(
|
||||
DEBUG_AND_RELEASE_AND_COVERAGE
|
||||
"Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild."
|
||||
)
|
||||
|
||||
find_package(Python3 COMPONENTS Interpreter)
|
||||
set(PYTHON3 Python3::Interpreter)
|
||||
set(CMAKE_INSTALL_DATADIR ${CMAKE_INSTALL_PREFIX})
|
||||
set(PYTHON3 ${Python3_EXECUTABLE})
|
||||
# See also CMake built-in; CMAKE_INSTALL_PREFIX is applied by the install command.
|
||||
set(CMAKE_INSTALL_DATADIR .)
|
||||
include(GNUInstallDirs)
|
||||
include(CMakePackageConfigHelpers)
|
||||
include(CheckStructHasMember)
|
||||
include(ExternalProject)
|
||||
include(FindThreads)
|
||||
|
||||
if (NOT WIN32)
|
||||
if(NOT WIN32)
|
||||
message(WARNING "CMake support on Linux/OSX is experimental.")
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
if (DEFINED ENV{WIN_FLEX_BISON})
|
||||
if(WIN32)
|
||||
if(DEFINED ENV{WIN_FLEX_BISON})
|
||||
set(WIN_FLEX_BISON "$ENV{WIN_FLEX_BISON}")
|
||||
endif()
|
||||
if (EXISTS ${WIN_FLEX_BISON})
|
||||
if(EXISTS ${WIN_FLEX_BISON})
|
||||
list(APPEND CMAKE_PREFIX_PATH ${WIN_FLEX_BISON})
|
||||
endif()
|
||||
if (NOT WIN_FLEX_BISON)
|
||||
message(FATAL_ERROR "Please install https://github.com/lexxmark/winflexbison and set WIN_FLEX_BISON environment variable. Please use install cmake target after a successful build.")
|
||||
if(NOT WIN_FLEX_BISON)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Please install https://github.com/lexxmark/winflexbison and set WIN_FLEX_BISON environment variable. Please use install cmake target after a successful build."
|
||||
)
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
endif()
|
||||
@@ -51,20 +59,25 @@ endif()
|
||||
set(OBJCACHE "" CACHE STRING "Path for ccache, auto-detected if empty")
|
||||
option(OBJCACHE_ENABLED "Compile Verilator with ccache" ON)
|
||||
|
||||
if (OBJCACHE_ENABLED)
|
||||
if (OBJCACHE STREQUAL "")
|
||||
if(OBJCACHE_ENABLED)
|
||||
if(OBJCACHE STREQUAL "")
|
||||
find_program(OBJCACHE_PATH ccache)
|
||||
if (OBJCACHE_PATH STREQUAL "OBJCACHE_PATH-NOTFOUND")
|
||||
if(OBJCACHE_PATH STREQUAL "OBJCACHE_PATH-NOTFOUND")
|
||||
set(OBJCACHE_PATH "")
|
||||
endif()
|
||||
else()
|
||||
set(OBJCACHE_PATH "${OBJCACHE}")
|
||||
endif()
|
||||
if (NOT OBJCACHE_PATH STREQUAL "")
|
||||
execute_process(COMMAND "${OBJCACHE_PATH}" --version
|
||||
OUTPUT_VARIABLE objcache_version)
|
||||
if(NOT OBJCACHE_PATH STREQUAL "")
|
||||
execute_process(
|
||||
COMMAND "${OBJCACHE_PATH}" --version
|
||||
OUTPUT_VARIABLE objcache_version
|
||||
)
|
||||
string(REGEX MATCH "[^\n\r]+" objcache_version "${objcache_version}")
|
||||
message(STATUS "Found ccache: ${OBJCACHE_PATH} (\"${objcache_version}\")")
|
||||
message(
|
||||
STATUS
|
||||
"Found ccache: ${OBJCACHE_PATH} (\"${objcache_version}\")"
|
||||
)
|
||||
set(CMAKE_CXX_COMPILER_LAUNCHER "${OBJCACHE_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
@@ -75,8 +88,8 @@ find_package(FLEX)
|
||||
# Build
|
||||
#set_property(GLOBAL PROPERTY JOB_POOLS one_job=1)
|
||||
|
||||
if (DEBUG_AND_RELEASE_AND_COVERAGE)
|
||||
if (CMAKE_GENERATOR MATCHES "^Visual Studio ")
|
||||
if(DEBUG_AND_RELEASE_AND_COVERAGE)
|
||||
if(CMAKE_GENERATOR MATCHES "^Visual Studio ")
|
||||
error("%Error: The DEBUG_AND_RELEASE_AND_COVERAGE option is not supported in MSBuild-based builds.")
|
||||
endif()
|
||||
set(saved_build_type ${CMAKE_BUILD_TYPE})
|
||||
@@ -95,42 +108,69 @@ endif()
|
||||
|
||||
set(PACKAGE_NAME ${PROJECT_NAME})
|
||||
set(PACKAGE_VERSION ${PROJECT_VERSION})
|
||||
set(CXX ${CMAKE_CXX_COMPILER})
|
||||
set(AR ${CMAKE_AR})
|
||||
|
||||
configure_file(include/verilated_config.h.in include/verilated_config.h @ONLY)
|
||||
configure_file(include/verilated.mk.in include/verilated.mk @ONLY)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/include/verilated_config.h DESTINATION ${CMAKE_INSTALL_PREFIX}/include)
|
||||
|
||||
configure_package_config_file(verilator-config.cmake.in verilator-config.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/include/verilated_config.h
|
||||
DESTINATION include
|
||||
)
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/include/verilated.mk
|
||||
DESTINATION include
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
|
||||
configure_package_config_file(verilator-config-version.cmake.in verilator-config-version.cmake
|
||||
INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}
|
||||
configure_package_config_file(
|
||||
verilator-config.cmake.in
|
||||
verilator-config.cmake
|
||||
INSTALL_DESTINATION .
|
||||
)
|
||||
|
||||
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config-version.cmake DESTINATION ${CMAKE_INSTALL_PREFIX})
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config.cmake
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
foreach (program
|
||||
configure_package_config_file(
|
||||
verilator-config-version.cmake.in
|
||||
verilator-config-version.cmake
|
||||
INSTALL_DESTINATION .
|
||||
)
|
||||
|
||||
install(
|
||||
FILES ${CMAKE_CURRENT_BINARY_DIR}/verilator-config-version.cmake
|
||||
DESTINATION .
|
||||
)
|
||||
|
||||
foreach(
|
||||
program
|
||||
verilator
|
||||
verilator_gantt
|
||||
verilator_ccache_report
|
||||
verilator_difftree
|
||||
verilator_profcfunc
|
||||
verilator_includer
|
||||
)
|
||||
install(PROGRAMS bin/${program} TYPE BIN)
|
||||
endforeach()
|
||||
|
||||
install(DIRECTORY examples TYPE DATA FILES_MATCHING
|
||||
install(
|
||||
DIRECTORY examples
|
||||
TYPE DATA
|
||||
FILES_MATCHING
|
||||
PATTERN "examples/*/*.[chv]*"
|
||||
PATTERN "examples/*/Makefile*"
|
||||
PATTERN "examples/*/CMakeLists.txt"
|
||||
)
|
||||
|
||||
install(DIRECTORY include TYPE DATA FILES_MATCHING
|
||||
install(
|
||||
DIRECTORY include
|
||||
TYPE DATA
|
||||
FILES_MATCHING
|
||||
PATTERN "include/verilated_config.h"
|
||||
PATTERN "include/verilated.mk"
|
||||
PATTERN "include/*.[chv]"
|
||||
PATTERN "include/*.cpp"
|
||||
PATTERN "include/*.sv"
|
||||
|
||||
@@ -8,6 +8,183 @@ The changes in each Verilator version are described below. The
|
||||
contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
Verilator 5.030 2024-10-27
|
||||
==========================
|
||||
|
||||
**Major:**
|
||||
|
||||
* Add `-output-groups` to build with concatenated .cpp files (#5257). [Mariusz Glebocki]
|
||||
* Self-tests have been converted to Python, run `{test_name}.py` instead of `{test_name}.pl`.
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Change .vlt config files to be read before .v files (#5185). [David Moberg]
|
||||
* Change to use maximum for cover point aggregation (#5402). [Andrew Nolte]
|
||||
* Change `--main` and `--binary` to use a TOP hierarchy name of "" (#5482).
|
||||
* Change install of public executables into bindir instead of pkgdatadir (#5140) (#5544). [Geza Lore]
|
||||
* Support IEEE-compliant intra-assign delays (#3711) (#5441). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support `wor`, `trior`, `wand`, `triand` (#5386) (#5496). [Zhou Shen]
|
||||
* Support unconstrained randomization for unions (#5395) (#5396). [Yilou Wang]
|
||||
* Support basic constrained queue randomization (#5413). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support packed/unpacked and dynamic array unconstrained randomization (#5414) (#5415). [Yilou Wang]
|
||||
* Support appending to queue via `[]` (#5421). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support named event locals (#5422). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support basic `dist` constraints (#5431). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support unpacked array constrained randomization (#5437) (#5489). [Yilou Wang]
|
||||
* Support inside array constraints (#5448). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support DPI imports and exports with double underscores (#5481).
|
||||
* Support ccache when compiling Verilated files with cmake.
|
||||
* Support `local` and `protected` on `typedef` (#5460).
|
||||
* Support unconstrained randomization for associative array and queue (#5515). [Yilou Wang]
|
||||
* Support `rand` dynamic arrays of objects (#5557) (#5564). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Add error on misused genvar (#408). [Alex Solomatnikov]
|
||||
* Add error on instances without parenthesis.
|
||||
* Add Docker pre-commit hook (#5238) (#5452). [Chris Bachhuber]
|
||||
* Add partial coverage symbol and branch data in lcov info files (#5388). [Andrew Nolte]
|
||||
* Add method to check if there are VPI callbacks of the given type (#5399). [Kaleb Barrett]
|
||||
* Remove warning on unsized numbers exceeding 32-bits.
|
||||
* Improve Verilation thread pool (#5161). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Improve performance of V3VariableOrder with parallelism (#5406). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Improve parser error handling (#5493). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Improve process trigger performance (#5483). [Geza Lore]
|
||||
* Fix suppression of WIDTH* warnings when immediately under a size cast (#3417).
|
||||
* Fix `$fatal` to not be affected by `+verilator+error+limit` (#5135). [Gökçe Aydos]
|
||||
* Fix equivalence checking when replacing type parameters (#5213) (#5255). [Han Qi]
|
||||
* Fix display with multiple string formats (#5311). [Luiza de Melo]
|
||||
* Fix performance of V3Trace when many activity blocks (#5372). [Deniz Güzel]
|
||||
* Fix REALCVT warning on integral timescale conversions (#5378). [Liam Braun]
|
||||
* Fix multidimensional function return value selects (#5382). [Gökçe Aydos]
|
||||
* Fix internal error in out-of-range select (#5393) (#5443). [Geza Lore]
|
||||
* Fix dot fallback finding wrong symbols (#5394). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix infinite recursion due to recursive functions/tasks (#5398). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix V3Randomize compile error on old GCC (#5403) (#5417). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix extra events in traces (#5405).
|
||||
* Fix empty `foreach` in `if` in constraints (#5408). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix queue `[$-i]` select as reference argument (#5411). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix `pre`/`post_randomize` on `randomize() with` (#5412). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix capturing params in `randomize() with` (#5416) (#5418). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix `sformatf` internal error on initial automatics (#5423). [Todd Strader]
|
||||
* Fix clearing trigger of events with no sensitivity trees (#5426). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix driving clocking block in reactive region (#5430). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix associative array next/prev/first/last mis-propagating constants (#5435). [Ethan Sifferman]
|
||||
* Fix randomize treated as std::randomize in classes (#5436). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix `foreach` colliding index names (#5444). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix fault on defparam with UNSUPPORTED ignored (#5450). [Luiza de Melo]
|
||||
* Fix class reference with pin that is a class reference (#5454).
|
||||
* Fix not reporting class reference with extra parameters (#5467).
|
||||
* Fix user-type parameter overlap (#5469). [Todd Strader]
|
||||
* Fix tracing when name() is empty (#5470). [Sam Shahrestani]
|
||||
* Fix timing mode not exiting on empty events (#5472).
|
||||
* Fix coverage counts missing due to table optimization (#5473) (#5474). [Vito Gamberini]
|
||||
* Fix `--binary` with .cpp PLI filenames under relative directory paths.
|
||||
* Fix extra dot in coverage point hierarchy when using name()=''.
|
||||
* Fix short-circuiting with associative array access (#5484). [Ethan Sifferman]
|
||||
* Fix short-circuiting on method calls (#5486). [Ethan Sifferman]
|
||||
* Fix exponential concatenate performance (#5488). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix V3Table trying to generate 'x' bits in the lookup table. (#5491). [Geza Lore]
|
||||
* Fix randomize with foreach constraints (#5492). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix explicit CMAKE_INSTALL_PREFIX usages (#5500). [Fabian Keßler]
|
||||
* Fix configure inserting absolute paths for Python and Perl (#5504) (#5505). [Nathan Graybeal]
|
||||
* Fix pattern initialization with typedef key (#5512). [Eugene Feinberg]
|
||||
* Fix `-j` option without argument in hierarchical Verilation (#5514). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix `foreach` with 2-D queues and dynamic arrays (#5525) (#5529). [Yilou Wang]
|
||||
* Fix struct array assignment (#5455) (#5537). [Yilou Wang]
|
||||
* Fix copy constructor of classes that use std::process (#5528). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix foreach on associative array (#5530). [Yilou Wang]
|
||||
* Fix multi-range indices assignment (#5534) (#5547). [Yilou Wang]
|
||||
* Fix static function wrappers (#5536). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix assignments of concatenation to queues and dynamic arrays (#5540). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix container reduction methods (#5542). [Krzysztof Boroński]
|
||||
* Fix complex user type problem with `--x-assign` (#5543). [Todd Strader]
|
||||
* Fix long module names crashing string handling (#5546). [Filip Badáň]
|
||||
* Fix array trace splitting (#5549). [Todd Strader]
|
||||
* Fix queue element access (#5551). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix struct literal on pattern assignment (#5552) (#5559). [Todd Strader]
|
||||
* Fix build on gcc when using the Spack wrapper (#5555). [Eric Müller]
|
||||
* Fix enum name method (#5563). [Todd Strader]
|
||||
* Fix `$countbits` in assert with non-tristates (#5566). [Shou-Li Hsu]
|
||||
|
||||
|
||||
Verilator 5.028 2024-08-21
|
||||
==========================
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Support state-dependent constraints (#5217). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support cross-module clocking variable access (#5184). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support inline constraints for class randomization methods (#5234). [Krzysztof Boroński]
|
||||
* Support clocking blocks in virtual interfaces (#5235). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support `$assertcontrol` assertion_type (#5236). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Support conditional constraints (#5245). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support`--compiler-include` headers in user-supplied cpp files (#5271). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Support `rand_mode` (#5273). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support `this.randomize with` (#5282). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support foreach constraints (#5302). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support `parameter type` in hierarchical blocks (#5309) (#5333). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Support assertcontrol directive type (#5310). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Support inline random variable control (#5317). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support streaming operator on arrays and wide data (#5326). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support streams to/from arrays of wide data (#5334). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support `constraint_mode` (#5338). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Support constraining AstSel (#5344). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Support default value on module input (#5358) (#5373). [Drew Ranck]
|
||||
* Add `--compiler-include` for additional C++ includes (#5139) (#5202). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Add `--emit-accessors` (#5182) (#5227). [Ryan Ziegler]
|
||||
* Add suggestions on misspelled PLI functions.
|
||||
* Add warning on dist in constraints (#5264). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Add more `rand_mode` unsupported errors (#5329). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Add parsing but otherwise ignore std::randomize (#5354). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Add Verilated cc define when `--timing` used (#5383). [Kaleb Barrett]
|
||||
* Improve emitted code to use a reference for VlSelf (#5254). [Yangyu Chen]
|
||||
* Fix monitor block sensitivity items (#4400) (#5294). [Udaya Raj Subedi]
|
||||
* Fix fusing macro arguments to not ignore whitespace (#5061). [Tudor Timi]
|
||||
* Fix optimized-out sensitivity trees with `--timing` (#5080) (#5349). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix classes/modules of case-similar names (#5109). [Arkadiusz Kozdra]
|
||||
* Fix mis-removing $value$plusargs calls (#5127) (#5137). [Seth Pellegrino]
|
||||
* Fix incorrect result of width mismatch (#5186) (#5189). [Yutetsu TAKATSUKASA]
|
||||
* Fix compiler coroutine check (#5190) (#5300). [Ricardo Barbedo]
|
||||
* Fix shortened module names when searching for files (#5196) (#5246). [Tim Hutt]
|
||||
* Fix `--x-assign` to be independent from `+verilator+rand+reset` (#5214). [Andrew Nolte]
|
||||
* Fix splitting if statements with impure conditions (#5219). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Fix unknown conversion on queues (#5220). [Alex Solomatnikov]
|
||||
* Fix top-level unpacked structure resets (#5221).
|
||||
* Fix concurrency for mailbox and semaphores (#5222). [Liam Braun]
|
||||
* Fix forks capturing non-input ports in tasks (#5237) (#5343). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix toggle coverage aggregation on same line (#5248). [Krzysztof Obłonczek]
|
||||
* Fix error on empty generate with -O0 (#5250).
|
||||
* Fix unconstrained randomization of unpacked structs (#5252). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix inlining of variables driven from forced vars (#5259). [Geza Lore]
|
||||
* Fix tracing with `--main-top-name -` (#5261). [Ethan Sifferman]
|
||||
* Fix randomization when used with inheritance (#5268). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix inline constraints creating class random generator (#5280). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix WIDTHEXPAND on left shift of intuitive amount (#5284). [Greg Taylor]
|
||||
* Fix elaborating foreach loops (#5285). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix initializing static array in dynamic arrays and queues (#5287). [Baruch Sterin]
|
||||
* Fix static variable initializers in procedures (#5296). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Fix randomizing current object with `rand` class instance member (#5292). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix handling of rand fields not referenced in constraints (#5305). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix Python3 path discovery in make flows to avoid mixing system and user python interpreters (#5307) [Markus Krause]
|
||||
* Fix make flows to pass PYTHON3 (like PERL) (#5307) (#5308). [Markus Krause]
|
||||
* Fix assert on wide expression (#5319) (#5324). [Varun Koyyalagunta]
|
||||
* Fix output clock variable overwriting signal (#5320) (#5347). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix stringify in nested preprocessor macros (#5323). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix $sformat with array arguments (#5330). [Abe Jordan]
|
||||
* Fix -Wunused-but-set-variable clang warning (#5331). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Fix purity of functions with AstJumpBlock or AstStmtExpr (#5332). [Ryszard Rozak, Antmicro Ltd.]
|
||||
* Fix compilation error on unreachable disable fork / wait fork (#5339). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix missing type coercion in 'inside {array}' (#5340). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix +: and -: unpacked array slicing when array has nonzero low index (#5345) (#5387). [James Bailey]
|
||||
* Fix tracing_{on,off} in the presence of non-inlined modules (#5346). [Geza Lore]
|
||||
* Fix NBAs in suspendables (#5348). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix lint_off on Errors (#5351) (#5363). [Ethan Sifferman]
|
||||
* Fix cache config file resolution performance (#5369). [Geza Lore]
|
||||
* Fix capturing fields from superclass in `randomize() with` (#5389). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix virtual interface null checks (#5391). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||
* Fix ==? and !=? with X values.
|
||||
* Fix CPU time being zero.
|
||||
* Fix inline function ref port persistence.
|
||||
|
||||
|
||||
Verilator 5.026 2024-06-15
|
||||
==========================
|
||||
|
||||
@@ -34,6 +211,7 @@ Verilator 5.026 2024-06-15
|
||||
* Add traceCapable indication to model header (#5053). [Vito Gamberini]
|
||||
* Add increasing of stack size when possible (#5071) (#5104). [Yinan Xu]
|
||||
* Add assertion on reusing VerilatedContext (#5167).
|
||||
* Add `--pins-sc-uint-bool` to force SystemC uint type (#5192). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Improve DFG regularization in cyclic graphs (#5142). [Geza Lore]
|
||||
* Improve VerilatedVpiPutHolder storage requirements (#5144). [Kaleb Barrett]
|
||||
* Fix coroutines without awaits to have a co_return (#4208) (#5175). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
@@ -72,7 +250,11 @@ Verilator 5.026 2024-06-15
|
||||
* Fix SystemC BITS_PER_DIGIT in VL_ASSIGN_SBW (#5170). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Fix non-constant replication in concats (#5171). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||
* Fix table optimization when applied on real data type (#5172) (#5173). [Arthur Rosa]
|
||||
* Fix signed types emitted in hierarchical Verilation (#5178). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||
* Fix DPI import of null C-string (#5179).
|
||||
* Fix CMake installation missing verilated.mk (#5187) (#5188). [Philip Axer]
|
||||
* Fix linking with pthreads on CMake (#5194). [Tim Hutt]
|
||||
* Fix clang-17 coroutines configuration with -std=gnu++20 (#5200). [Gus Smith]
|
||||
|
||||
|
||||
Verilator 5.024 2024-04-05
|
||||
@@ -123,9 +305,10 @@ Verilator 5.024 2024-04-05
|
||||
* Fix preprocessor to respect strings in joins (#5007).
|
||||
* Fix tracing class parameters (#5014).
|
||||
* Fix memory leaks (#5016). [Geza Lore]
|
||||
* Fix $readmem with missing newline (#5019). [Josse Van Delm]
|
||||
* Fix `$readmem` with missing newline (#5019). [Josse Van Delm]
|
||||
* Fix internal error on missing pattern key (#5023).
|
||||
* Fix tracing replicated hierarchical models (#5027).
|
||||
* Fix false LIFETIME warning on `repeat` in `fork-join` (#5456).
|
||||
|
||||
|
||||
Verilator 5.022 2024-02-24
|
||||
@@ -464,7 +647,7 @@ Verilator 5.012 2023-06-13
|
||||
* Fix wide structure VL_TOSTRING_W generation (#4188) (#4189). [Aylon Chaim Porat]
|
||||
* Fix references to members of parameterized base classes (#4196). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix tracing undefined alignment (#4201) (#4288) [John Wehle]
|
||||
* Fix class specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250). [John Wehle]
|
||||
* Fix class-specific same methods for AstVarScope, AstVar, and AstScope (#4203) (#4250). [John Wehle]
|
||||
* Fix dotted references in parameterized classes (#4206). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix bit selections under parameterized classes (#4210). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix duplicate std:: declaration with -I (#4215). [Harald Pretl]
|
||||
@@ -620,7 +803,7 @@ Verilator 5.006 2023-01-22
|
||||
**Minor:**
|
||||
|
||||
* Support clocking blocks (#3674). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Support packed structs (#3802). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Support unpacked structs (#3802). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Support Windows-native builds using cmake (#3814). [Kritik Bhimani]
|
||||
* Support p format for UnpackArray (#3877). [Aleksander Kiryk, Antmicro Ltd]
|
||||
* Support property calls without parenthesis (#3879) (#3893). [Ryszard Rozak, Antmicro Ltd]
|
||||
@@ -1511,6 +1694,7 @@ Verilator 4.026 2020-01-11
|
||||
* Fix expand optimization slowing --lint-only. Closes #2091. [Thomas Watts]
|
||||
* Fix %{number}s with strings. #2093. [agrobman]
|
||||
* Fix shebang breaking some shells. Closes #2067. [zdave]
|
||||
* Fix errors on using string in incorrect format (#5240). [John Demme]
|
||||
|
||||
|
||||
Verilator 4.024 2019-12-08
|
||||
|
||||
+91
-34
@@ -52,6 +52,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MAKEINFO = makeinfo
|
||||
POD2TEXT = pod2text
|
||||
PYTHON3 = @PYTHON3@
|
||||
MKINSTALLDIRS = $(SHELL) $(srcdir)/src/mkinstalldirs
|
||||
|
||||
# Version (for docs/guide/conf.py)
|
||||
@@ -76,7 +77,7 @@ datadir = @datadir@
|
||||
# Directory in which to install documentation info files.
|
||||
infodir = @infodir@
|
||||
|
||||
# Directory in which to install package specific files
|
||||
# Directory in which to install package-specific files
|
||||
# Generally ${prefix}/share/verilator
|
||||
pkgdatadir = @pkgdatadir@
|
||||
|
||||
@@ -96,6 +97,7 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
######################################################################
|
||||
# Main build targets
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
@@ -146,6 +148,9 @@ verilator_exe verilator_bin$(EXEEXT) verilator_bin_dbg$(EXEEXT) verilator_covera
|
||||
@echo "making verilator in src"
|
||||
$(MAKE) -C src $(OBJCACHE_JOBS)
|
||||
|
||||
######################################################################
|
||||
# Tests
|
||||
|
||||
.PHONY:msg_test
|
||||
msg_test: all_nomsg
|
||||
@echo "Build complete!"
|
||||
@@ -156,7 +161,7 @@ msg_test: all_nomsg
|
||||
.PHONY: test
|
||||
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
||||
test: smoke-test test_regress
|
||||
# examples is part of test_regress's test_regress/t/t_a2_examples.pl
|
||||
# examples is part of test_regress's test_regress/t/t_a2_examples.py
|
||||
# (because that allows it to run in parallel with other test_regress's)
|
||||
else
|
||||
test: smoke-test examples
|
||||
@@ -168,8 +173,8 @@ endif
|
||||
@echo
|
||||
|
||||
smoke-test: all_nomsg
|
||||
test_regress/t/t_a1_first_cc.pl
|
||||
test_regress/t/t_a2_first_sc.pl
|
||||
test_regress/t/t_a1_first_cc.py
|
||||
test_regress/t/t_a2_first_sc.py
|
||||
|
||||
test_regress: all_nomsg
|
||||
$(MAKE) -C test_regress
|
||||
@@ -183,6 +188,9 @@ examples: all_nomsg
|
||||
$(MAKE) -C $$p VERILATOR_ROOT=`pwd` || exit 10; \
|
||||
done
|
||||
|
||||
######################################################################
|
||||
# Docs
|
||||
|
||||
.PHONY: docs
|
||||
docs: info
|
||||
|
||||
@@ -204,6 +212,20 @@ verilator.html:
|
||||
verilator.pdf: Makefile
|
||||
$(MAKE) -C docs verilator.pdf
|
||||
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
|
||||
${srcdir}/*.in ${srcdir}/*.pod
|
||||
|
||||
TAGS: $(TAGFILES)
|
||||
etags $(TAGFILES)
|
||||
|
||||
.PHONY: doxygen
|
||||
|
||||
doxygen:
|
||||
$(MAKE) -C docs doxygen
|
||||
|
||||
######################################################################
|
||||
# Install
|
||||
|
||||
# Public executables intended to be invoked directly by the user
|
||||
# Don't put wildcards in these variables, it might cause an uninstall of other stuff
|
||||
VL_INST_PUBLIC_SCRIPT_FILES = verilator \
|
||||
@@ -244,11 +266,15 @@ mkbindirs:
|
||||
installbin: | mkbindirs
|
||||
cd $(srcdir)/bin; \
|
||||
for p in $(VL_INST_PUBLIC_SCRIPT_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/bin/$$p; \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
|
||||
done
|
||||
perl -p -i -e 'use File::Spec;' \
|
||||
-e' $$path = File::Spec->abs2rel("$(realpath $(DESTDIR)$(pkgdatadir))", "$(realpath $(DESTDIR)$(bindir))");' \
|
||||
-e 's/my \$$verilator_pkgdatadir_relpath = .*/my \$$verilator_pkgdatadir_relpath = "$$path";/g' \
|
||||
-- "$(DESTDIR)/$(bindir)/verilator"
|
||||
cd bin; \
|
||||
for p in $(VL_INST_PUBLIC_BIN_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/bin/$$p; \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
|
||||
done
|
||||
cd $(srcdir)/bin; \
|
||||
for p in $(VL_INST_PRIVATE_SCRIPT_FILES) ; do \
|
||||
@@ -258,11 +284,11 @@ installbin: | mkbindirs
|
||||
installredirect: installbin | mkbindirs
|
||||
cp ${srcdir}/bin/redirect ${srcdir}/bin/redirect.tmp
|
||||
perl -p -i -e 'use File::Spec;' \
|
||||
-e' $$path = File::Spec->abs2rel("$(realpath $(DESTDIR)$(pkgdatadir)/bin)", "$(realpath $(DESTDIR)$(bindir))");' \
|
||||
-e' $$path = File::Spec->abs2rel("$(realpath $(DESTDIR)$(bindir))", "$(realpath $(DESTDIR)$(pkgdatadir)/bin)");' \
|
||||
-e 's/RELPATH.*/"$$path";/g' -- "${srcdir}/bin/redirect.tmp"
|
||||
cd $(srcdir)/bin; \
|
||||
for p in $(VL_INST_PUBLIC_SCRIPT_FILES) $(VL_INST_PUBLIC_BIN_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) redirect.tmp $(DESTDIR)$(bindir)/$$p; \
|
||||
$(INSTALL_PROGRAM) redirect.tmp $(DESTDIR)$(pkgdatadir)/bin/$$p; \
|
||||
done
|
||||
rm ${srcdir}/bin/redirect.tmp
|
||||
|
||||
@@ -344,6 +370,19 @@ install-all: installbin installredirect installman installdata install-msg
|
||||
|
||||
install-here: installman info
|
||||
|
||||
install-msg:
|
||||
@echo
|
||||
@echo "Installed binaries to $(DESTDIR)$(bindir)/verilator"
|
||||
@echo "Installed man to $(DESTDIR)$(mandir)/man1"
|
||||
@echo "Installed examples to $(DESTDIR)$(pkgdatadir)/examples"
|
||||
@echo
|
||||
@echo "For documentation see 'man verilator' or 'verilator --help'"
|
||||
@echo "For forums and to report bugs see https://verilator.org"
|
||||
@echo
|
||||
|
||||
######################################################################
|
||||
# Format/Lint
|
||||
|
||||
# Use --xml flag to see the cppcheck code to use for suppression
|
||||
CPPCHECK1_CPP = $(wildcard $(srcdir)/include/*.cpp)
|
||||
CPPCHECK2_CPP = $(wildcard $(srcdir)/examples/*/*.cpp)
|
||||
@@ -411,7 +450,8 @@ analyzer-include:
|
||||
-rm -rf examples/*/obj*
|
||||
scan-build $(MAKE) -k examples
|
||||
|
||||
format: clang-format yapf format-pl-exec
|
||||
format:
|
||||
$(MAKE) -j 4 clang-format yapf format-exec
|
||||
|
||||
CLANGFORMAT = clang-format-14
|
||||
CLANGFORMAT_FLAGS = -i
|
||||
@@ -422,6 +462,20 @@ clang-format:
|
||||
|| echo "*** You are not using clang-format-14, indents may differ from master's ***"
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
||||
|
||||
YAMLFIX = YAMLFIX_WHITELINES=1 YAMLFIX_LINE_LENGTH=130 YAMLFIX_preserve_quotes=true yamlfix
|
||||
|
||||
yamlfix:
|
||||
$(YAMLFIX) .
|
||||
|
||||
# CMake files
|
||||
CMAKE_FILES = \
|
||||
CMakeLists.txt \
|
||||
examples/*/CMakeLists.txt \
|
||||
src/CMakeLists.txt \
|
||||
test_regress/CMakeLists.txt \
|
||||
*.cmake.in \
|
||||
|
||||
# Python programs, subject to format and lint
|
||||
PY_PROGRAMS = \
|
||||
bin/verilator_ccache_report \
|
||||
bin/verilator_difftree \
|
||||
@@ -440,6 +494,7 @@ PY_PROGRAMS = \
|
||||
src/flexfix \
|
||||
src/vlcovgen \
|
||||
src/.gdbinit.py \
|
||||
test_regress/*.py \
|
||||
test_regress/t/*.pf \
|
||||
nodist/clang_check_attributes \
|
||||
nodist/code_coverage \
|
||||
@@ -447,45 +502,55 @@ PY_PROGRAMS = \
|
||||
nodist/fuzzer/actual_fail \
|
||||
nodist/fuzzer/generate_dictionary \
|
||||
nodist/install_test \
|
||||
nodist/log_changes \
|
||||
|
||||
# Python files, subject to format but not lint
|
||||
PY_FILES = \
|
||||
$(PY_PROGRAMS) \
|
||||
nodist/code_coverage.dat \
|
||||
test_regress/t/*.py \
|
||||
|
||||
# Python files, test_regress tests
|
||||
PY_TEST_FILES = \
|
||||
test_regress/t/*.py \
|
||||
|
||||
YAPF = yapf3
|
||||
YAPF_FLAGS = -i
|
||||
YAPF_FLAGS = -i --parallel
|
||||
|
||||
yapf:
|
||||
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
|
||||
|
||||
GERSEMI = gersemi
|
||||
GERSEMI_FLAGS = -i
|
||||
|
||||
format-cmake:
|
||||
$(GERSEMI) $(GERSEMI_FLAGS) $(CMAKE_FILES)
|
||||
|
||||
PYLINT = pylint
|
||||
PYLINT_FLAGS = --score=n --disable=R0801
|
||||
PYLINT_FLAGS = --recursive=n --score=n --disable=R0801
|
||||
PYLINT_TEST_FLAGS = $(PYLINT_FLAGS) --disable=C0103,C0114,C0116,C0209,C0411,C0413,C0301,R0801,R0912,R0915,R0916,R1702,W0511,W0621
|
||||
|
||||
RUFF = ruff
|
||||
RUFF_FLAGS = check --ignore=E402,E501,E701
|
||||
|
||||
# "make -k" so can see all tool result errors
|
||||
lint-py:
|
||||
$(MAKE) -k lint-py-pylint lint-py-ruff
|
||||
$(MAKE) -k lint-py-pylint lint-py-pylint-tests lint-py-ruff
|
||||
|
||||
lint-py-pylint:
|
||||
$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS)
|
||||
|
||||
lint-py-pylint-tests:
|
||||
$(PYLINT) $(PYLINT_TEST_FLAGS) $(PY_TEST_FILES) | $(PYTHON3) nodist/lint_py_test_filter
|
||||
|
||||
lint-py-ruff:
|
||||
$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
|
||||
|
||||
format-pl-exec:
|
||||
-chmod a+x test_regress/t/*.pl
|
||||
format-exec:
|
||||
-chmod a+x test_regress/t/*.py
|
||||
|
||||
install-msg:
|
||||
@echo
|
||||
@echo "Installed binaries to $(DESTDIR)$(bindir)/verilator"
|
||||
@echo "Installed man to $(DESTDIR)$(mandir)/man1"
|
||||
@echo "Installed examples to $(DESTDIR)$(pkgdatadir)/examples"
|
||||
@echo
|
||||
@echo "For documentation see 'man verilator' or 'verilator --help'"
|
||||
@echo "For forums and to report bugs see https://verilator.org"
|
||||
@echo
|
||||
######################################################################
|
||||
# Configure
|
||||
|
||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
||||
|
||||
@@ -506,6 +571,9 @@ else
|
||||
autoconf
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
# Clean
|
||||
|
||||
maintainer-clean::
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "rebuilding the deleted files requires autoconf."
|
||||
@@ -536,17 +604,6 @@ distclean maintainer-clean::
|
||||
rm -f bin/verilator_bin* bin/verilator_coverage_bin*
|
||||
rm -f include/verilated.mk include/verilated_config.h
|
||||
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
|
||||
${srcdir}/*.in ${srcdir}/*.pod
|
||||
|
||||
TAGS: $(TAGFILES)
|
||||
etags $(TAGFILES)
|
||||
|
||||
.PHONY: doxygen
|
||||
|
||||
doxygen:
|
||||
$(MAKE) -C docs doxygen
|
||||
|
||||
######################################################################
|
||||
# Distributions
|
||||
|
||||
|
||||
+10
-3
@@ -69,7 +69,9 @@ if (! GetOptions(
|
||||
pod2usage(-exitstatus => 2, -verbose => 0);
|
||||
}
|
||||
|
||||
my $verilator_root = realpath("$RealBin/..");
|
||||
# WARNING: $verilator_pkgdatadir_relpath is substituted during Verilator 'make install'
|
||||
my $verilator_pkgdatadir_relpath = "..";
|
||||
my $verilator_root = realpath("$RealBin/$verilator_pkgdatadir_relpath");
|
||||
if (defined $ENV{VERILATOR_ROOT}) {
|
||||
if ((!-d $ENV{VERILATOR_ROOT}) || $verilator_root ne realpath($ENV{VERILATOR_ROOT})) {
|
||||
warn "%Error: verilator: VERILATOR_ROOT is set to inconsistent path. Suggest leaving it unset.\n";
|
||||
@@ -324,6 +326,7 @@ detailed descriptions of these arguments.
|
||||
--clk <signal-name> Mark specified signal as clock
|
||||
--no-clk <signal-name> Prevent marking specified signal as clock
|
||||
--compiler <compiler-name> Tune for specified C++ compiler
|
||||
--compiler-include Include additional header in the precompiled one
|
||||
--converge-limit <loops> Tune convergence settle time
|
||||
--coverage Enable all coverage
|
||||
--coverage-line Enable line coverage
|
||||
@@ -356,6 +359,7 @@ detailed descriptions of these arguments.
|
||||
--dumpi-tree-json <level> Enable dumping Ast .tree.json files at level
|
||||
--dumpi-<srcfile> <level> Enable dumping everything in source file at level
|
||||
-E Preprocess, but do not compile
|
||||
--emit-accessors Emit getter and setter methods for model top class
|
||||
--error-limit <value> Abort after this number of errors
|
||||
--exe Link to create executable
|
||||
--expand-limit <value> Set expand optimization limit
|
||||
@@ -375,6 +379,7 @@ detailed descriptions of these arguments.
|
||||
--get-supported <feature> Get if feature is supported
|
||||
--help Show this help
|
||||
--hierarchical Enable hierarchical Verilation
|
||||
--hierarchical-params-file <name> Internal option that specifies parameters file for hier blocks
|
||||
-I<dir> Directory to search for includes
|
||||
--if-depth <value> Tune IFDEPTH warning
|
||||
+incdir+<dir> Directory to search for includes
|
||||
@@ -402,6 +407,7 @@ detailed descriptions of these arguments.
|
||||
-O3 High-performance optimizations
|
||||
-O<optimization-letter> Selectable optimizations
|
||||
-o <executable> Name of final executable
|
||||
--output-groups <numfiles> Group .cpp files into larger ones
|
||||
--output-split <statements> Split .cpp files into pieces
|
||||
--output-split-cfuncs <statements> Split model functions
|
||||
--output-split-ctrace <statements> Split tracing functions
|
||||
@@ -410,6 +416,7 @@ detailed descriptions of these arguments.
|
||||
--pins-inout-enables Specify that __en and __out signals be created for inouts
|
||||
--pins-sc-biguint Specify types for top-level ports
|
||||
--pins-sc-uint Specify types for top-level ports
|
||||
--pins-sc-uint-bool Specify types for top-level ports
|
||||
--pins-uint8 Specify types for top-level ports
|
||||
--no-pins64 Don't use uint64_t's for 33-64 bit sigs
|
||||
--pipe-filter <command> Filter all input through a script
|
||||
@@ -459,8 +466,8 @@ detailed descriptions of these arguments.
|
||||
--trace-coverage Enable tracing of coverage
|
||||
--trace-depth <levels> Depth of tracing
|
||||
--trace-fst Enable FST waveform creation
|
||||
--trace-max-array <depth> Maximum bit width for tracing
|
||||
--trace-max-width <width> Maximum array depth for tracing
|
||||
--trace-max-array <depth> Maximum array depth for tracing
|
||||
--trace-max-width <width> Maximum bit width for tracing
|
||||
--trace-params Enable tracing of parameters
|
||||
--trace-structs Enable tracing structure names
|
||||
--trace-threads <threads> Enable FST waveform creation on separate threads
|
||||
|
||||
@@ -16,8 +16,7 @@ parser = argparse.ArgumentParser(
|
||||
|
||||
For documentation see
|
||||
https://verilator.org/guide/latest/exe_verilator_ccache_report.html""",
|
||||
epilog=
|
||||
"""Copyright 2002-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2002-2024 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.
|
||||
@@ -67,30 +66,23 @@ else:
|
||||
wnames = max(len(_) for _ in results) + 1
|
||||
wresults = max(len(_) for _ in results.values()) + 1
|
||||
for k in sorted(results.keys()):
|
||||
args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format(
|
||||
k,
|
||||
results[k],
|
||||
elapsed[k].total_seconds(),
|
||||
wnames=wnames,
|
||||
wresults=wresults))
|
||||
args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format(k,
|
||||
results[k],
|
||||
elapsed[k].total_seconds(),
|
||||
wnames=wnames,
|
||||
wresults=wresults))
|
||||
|
||||
args.o.write("\nSummary:\n")
|
||||
counts = collections.Counter(_ for _ in results.values())
|
||||
total = sum(counts.values())
|
||||
for k in sorted(counts.keys()):
|
||||
c = counts[k]
|
||||
args.o.write("{:{width}}| {} ({:.2%})\n".format(k,
|
||||
c,
|
||||
c / total,
|
||||
width=wresults))
|
||||
args.o.write("{:{width}}| {} ({:.2%})\n".format(k, c, c / total, width=wresults))
|
||||
|
||||
args.o.write("\nLongest:\n")
|
||||
longest = sorted(list(elapsed.items()),
|
||||
key=lambda kv: -kv[1].total_seconds())
|
||||
longest = sorted(list(elapsed.items()), key=lambda kv: -kv[1].total_seconds())
|
||||
for i, (k, v) in enumerate(longest):
|
||||
args.o.write("{:{width}}| {}s\n".format(k,
|
||||
v.total_seconds(),
|
||||
width=wnames))
|
||||
args.o.write("{:{width}}| {}s\n".format(k, v.total_seconds(), width=wnames))
|
||||
if i > 4:
|
||||
break
|
||||
|
||||
|
||||
@@ -47,8 +47,7 @@ def diff_dir(a, b):
|
||||
diff_file(a, b)
|
||||
anyfile = True
|
||||
if not anyfile:
|
||||
sys.stderr.write(
|
||||
"%Warning: No .tree files found that have similar base names\n")
|
||||
sys.stderr.write("%Warning: No .tree files found that have similar base names\n")
|
||||
|
||||
|
||||
def diff_file(a, b):
|
||||
@@ -109,18 +108,14 @@ parser = argparse.ArgumentParser(
|
||||
Verilator_difftree is used for debugging Verilator tree output files.
|
||||
It performs a diff between two files, or all files common between two
|
||||
directories, ignoring irrelevant pointer differences.""",
|
||||
epilog=
|
||||
"""Copyright 2005-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2005-2024 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""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('--no-lineno',
|
||||
action='store_false',
|
||||
help='do not show differences in line numbering')
|
||||
|
||||
+27
-54
@@ -15,11 +15,7 @@ LongestVcdStrValueLength = 0
|
||||
Threads = collections.defaultdict(lambda: []) # List of records per thread id
|
||||
Mtasks = collections.defaultdict(lambda: {'elapsed': 0, 'end': 0})
|
||||
Cpus = collections.defaultdict(lambda: {'mtask_time': 0})
|
||||
Global = {
|
||||
'args': {},
|
||||
'cpuinfo': collections.defaultdict(lambda: {}),
|
||||
'stats': {}
|
||||
}
|
||||
Global = {'args': {}, 'cpuinfo': collections.defaultdict(lambda: {}), 'stats': {}}
|
||||
ElapsedTime = None # total elapsed time
|
||||
ExecGraphTime = 0 # total elapsed time excuting an exec graph
|
||||
ExecGraphIntervals = [] # list of (start, end) pairs
|
||||
@@ -31,8 +27,7 @@ def read_data(filename):
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
|
||||
re_record = re.compile(r'^VLPROFEXEC (\S+) (\d+)(.*)$')
|
||||
re_payload_mtaskBegin = re.compile(
|
||||
r'id (\d+) predictStart (\d+) cpu (\d+)')
|
||||
re_payload_mtaskBegin = re.compile(r'id (\d+) predictStart (\d+) cpu (\d+)')
|
||||
re_payload_mtaskEnd = re.compile(r'id (\d+) predictCost (\d+)')
|
||||
|
||||
re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*')
|
||||
@@ -57,8 +52,7 @@ def read_data(filename):
|
||||
tick = int(tick)
|
||||
payload = payload.strip()
|
||||
if kind == "SECTION_PUSH":
|
||||
LongestVcdStrValueLength = max(LongestVcdStrValueLength,
|
||||
len(payload))
|
||||
LongestVcdStrValueLength = max(LongestVcdStrValueLength, len(payload))
|
||||
SectionStack.append(payload)
|
||||
Sections.append((tick, tuple(SectionStack)))
|
||||
elif kind == "SECTION_POP":
|
||||
@@ -66,15 +60,13 @@ def read_data(filename):
|
||||
SectionStack.pop()
|
||||
Sections.append((tick, tuple(SectionStack)))
|
||||
elif kind == "MTASK_BEGIN":
|
||||
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(
|
||||
payload).groups()
|
||||
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(payload).groups()
|
||||
mtask = int(mtask)
|
||||
predict_start = int(predict_start)
|
||||
ecpu = int(ecpu)
|
||||
mTaskThread[mtask] = thread
|
||||
records = Threads[thread]
|
||||
assert not records or records[-1]['start'] <= records[-1][
|
||||
'end'] <= tick
|
||||
assert not records or records[-1]['start'] <= records[-1]['end'] <= tick
|
||||
records.append({
|
||||
'start': tick,
|
||||
'mtask': mtask,
|
||||
@@ -85,8 +77,7 @@ def read_data(filename):
|
||||
Mtasks[mtask]['thread'] = thread
|
||||
Mtasks[mtask]['predict_start'] = predict_start
|
||||
elif kind == "MTASK_END":
|
||||
mtask, predict_cost = re_payload_mtaskEnd.match(
|
||||
payload).groups()
|
||||
mtask, predict_cost = re_payload_mtaskEnd.match(payload).groups()
|
||||
mtask = int(mtask)
|
||||
predict_cost = int(predict_cost)
|
||||
begin = Mtasks[mtask]['begin']
|
||||
@@ -163,8 +154,7 @@ def report():
|
||||
|
||||
print("\nSummary:")
|
||||
print(" Total elapsed time = {} rdtsc ticks".format(ElapsedTime))
|
||||
print(" Parallelized code = {:.2%} of elapsed time".format(
|
||||
ExecGraphTime / ElapsedTime))
|
||||
print(" Parallelized code = {:.2%} of elapsed time".format(ExecGraphTime / ElapsedTime))
|
||||
print(" Total threads = %d" % nthreads)
|
||||
print(" Total CPUs used = %d" % ncpus)
|
||||
print(" Total mtasks = %d" % len(Mtasks))
|
||||
@@ -176,15 +166,12 @@ def report():
|
||||
|
||||
if nthreads > ncpus:
|
||||
print()
|
||||
print("%%Warning: There were fewer CPUs (%d) than threads (%d)." %
|
||||
(ncpus, nthreads))
|
||||
print("%%Warning: There were fewer CPUs (%d) than threads (%d)." % (ncpus, nthreads))
|
||||
print(" : See docs on use of numactl.")
|
||||
else:
|
||||
if 'cpu_socket_cores_warning' in Global:
|
||||
print()
|
||||
print(
|
||||
"%Warning: Multiple threads scheduled on same hyperthreaded core."
|
||||
)
|
||||
print("%Warning: Multiple threads scheduled on same hyperthreaded core.")
|
||||
print(" : See docs on use of numactl.")
|
||||
if 'cpu_sockets_warning' in Global:
|
||||
print()
|
||||
@@ -228,8 +215,7 @@ def report_mtasks():
|
||||
serialTime = ElapsedTime - ExecGraphTime
|
||||
|
||||
def subReport(elapsed, work):
|
||||
print(" Thread utilization = {:7.2%}".format(work /
|
||||
(elapsed * nthreads)))
|
||||
print(" Thread utilization = {:7.2%}".format(work / (elapsed * nthreads)))
|
||||
print(" Speedup = {:6.3}x".format(work / elapsed))
|
||||
|
||||
print("\nParallelized code, measured:")
|
||||
@@ -256,8 +242,7 @@ def report_mtasks():
|
||||
if Mtasks[mtask]['elapsed'] > 0:
|
||||
if Mtasks[mtask]['predict_cost'] == 0:
|
||||
Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below
|
||||
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
|
||||
Mtasks[mtask]['elapsed'])
|
||||
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] / Mtasks[mtask]['elapsed'])
|
||||
p2e_ratios.append(p2e_ratio)
|
||||
|
||||
if p2e_ratio > max_p2e:
|
||||
@@ -269,18 +254,14 @@ def report_mtasks():
|
||||
|
||||
print("\nMTask statistics:")
|
||||
print(" Longest mtask id = {}".format(long_mtask))
|
||||
print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".
|
||||
format(long_mtask_time / ExecGraphTime))
|
||||
print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".format(
|
||||
long_mtask_time / ExecGraphTime))
|
||||
print(" min log(p2e) = %0.3f" % min_p2e, end="")
|
||||
|
||||
print(" from mtask %d (predict %d," %
|
||||
(min_mtask, Mtasks[min_mtask]['predict_cost']),
|
||||
end="")
|
||||
print(" from mtask %d (predict %d," % (min_mtask, Mtasks[min_mtask]['predict_cost']), end="")
|
||||
print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
|
||||
print(" max log(p2e) = %0.3f" % max_p2e, end="")
|
||||
print(" from mtask %d (predict %d," %
|
||||
(max_mtask, Mtasks[max_mtask]['predict_cost']),
|
||||
end="")
|
||||
print(" from mtask %d (predict %d," % (max_mtask, Mtasks[max_mtask]['predict_cost']), end="")
|
||||
print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
|
||||
|
||||
stddev = statistics.pstdev(p2e_ratios)
|
||||
@@ -315,8 +296,8 @@ def report_cpus():
|
||||
model = cpuinfo['model_name']
|
||||
|
||||
print(" {:3d} | {:7.2%} / {:16d} | {:>6s} | {:>4s} | {}".format(
|
||||
cpu, Cpus[cpu]['mtask_time'] / ElapsedTime,
|
||||
Cpus[cpu]['mtask_time'], socket, core, model))
|
||||
cpu, Cpus[cpu]['mtask_time'] / ElapsedTime, Cpus[cpu]['mtask_time'], socket, core,
|
||||
model))
|
||||
|
||||
if len(Global['cpu_sockets']) > 1:
|
||||
Global['cpu_sockets_warning'] = True
|
||||
@@ -366,8 +347,8 @@ def report_sections():
|
||||
|
||||
def printTree(prefix, name, entries, tree):
|
||||
print(" {:7.2%} | {:7.2%} | {:8} | {:10.2f} | {}".format(
|
||||
treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2],
|
||||
tree[2] / entries, prefix + name))
|
||||
treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2], tree[2] / entries,
|
||||
prefix + name))
|
||||
for k in sorted(tree[1], key=lambda _: -treeSum(tree[1][_])):
|
||||
printTree(prefix + " ", k, tree[2], tree[1][k])
|
||||
|
||||
@@ -438,10 +419,8 @@ def write_vcd(filename):
|
||||
addValue(code, start, mtask)
|
||||
addValue(code, end, None)
|
||||
|
||||
tStart = sorted(_['start'] for records in Threads.values()
|
||||
for _ in records)
|
||||
tEnd = sorted(_['end'] for records in Threads.values()
|
||||
for _ in records)
|
||||
tStart = sorted(_['start'] for records in Threads.values() for _ in records)
|
||||
tEnd = sorted(_['end'] for records in Threads.values() for _ in records)
|
||||
|
||||
# Predicted graph
|
||||
for start, end in ExecGraphIntervals:
|
||||
@@ -455,11 +434,10 @@ def write_vcd(filename):
|
||||
# Predict mtasks that fill the time the execution occupied
|
||||
for mtask in Mtasks:
|
||||
thread = Mtasks[mtask]['thread']
|
||||
pred_scaled_start = start + int(
|
||||
Mtasks[mtask]['predict_start'] * measured_scaling)
|
||||
pred_scaled_start = start + int(Mtasks[mtask]['predict_start'] * measured_scaling)
|
||||
pred_scaled_end = start + int(
|
||||
(Mtasks[mtask]['predict_start'] +
|
||||
Mtasks[mtask]['predict_cost']) * measured_scaling)
|
||||
(Mtasks[mtask]['predict_start'] + Mtasks[mtask]['predict_cost']) *
|
||||
measured_scaling)
|
||||
if pred_scaled_start == pred_scaled_end:
|
||||
continue
|
||||
|
||||
@@ -545,8 +523,7 @@ Verilator_gantt creates a visual representation to help analyze Verilator
|
||||
|
||||
For documentation see
|
||||
https://verilator.org/guide/latest/exe_verilator_gantt.html""",
|
||||
epilog=
|
||||
"""Copyright 2018-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2018-2024 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.
|
||||
@@ -554,12 +531,8 @@ Version 2.0.
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
|
||||
parser.add_argument('--debug', action='store_true', help='enable debug')
|
||||
parser.add_argument('--no-vcd',
|
||||
help='disable creating vcd',
|
||||
action='store_true')
|
||||
parser.add_argument('--vcd',
|
||||
help='filename for vcd outpue',
|
||||
default='profile_exec.vcd')
|
||||
parser.add_argument('--no-vcd', help='disable creating vcd', action='store_true')
|
||||
parser.add_argument('--vcd', help='filename for vcd outpue', default='profile_exec.vcd')
|
||||
parser.add_argument('filename',
|
||||
help='input profile_exec.dat filename to process',
|
||||
default='profile_exec.dat')
|
||||
|
||||
+11
-22
@@ -34,9 +34,8 @@ def profcfunc(filename):
|
||||
|
||||
# Older gprofs have no call column for single-call functions
|
||||
# %time cumesec selfsec {stuff} name
|
||||
match = re.match(
|
||||
r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
|
||||
line)
|
||||
match = re.match(r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
|
||||
line)
|
||||
if match:
|
||||
pct = float(match.group(1))
|
||||
sec = float(match.group(2))
|
||||
@@ -136,19 +135,15 @@ def profcfunc(filename):
|
||||
|
||||
design_width = 1
|
||||
for func, func_item in vfuncs.items():
|
||||
if design_width < len(func_item['design']):
|
||||
design_width = len(func_item['design'])
|
||||
design_width = max(design_width, len(func_item['design']))
|
||||
|
||||
print("Verilog code profile:")
|
||||
print(" These are split into three categories:")
|
||||
print(" C++: Time in non-Verilated C++ code")
|
||||
print(" Prof: Time in profile overhead")
|
||||
print(" VBlock: Time attributable to a block in a" +
|
||||
" Verilog file and line")
|
||||
print(" VCommon: Time in a Verilated module," +
|
||||
" due to all parts of the design")
|
||||
print(" VLib: Time in Verilated common libraries," +
|
||||
" called by the Verilated code")
|
||||
print(" VBlock: Time attributable to a block in a" + " Verilog file and line")
|
||||
print(" VCommon: Time in a Verilated module," + " due to all parts of the design")
|
||||
print(" VLib: Time in Verilated common libraries," + " called by the Verilated code")
|
||||
print()
|
||||
|
||||
print(" % cumulative self ")
|
||||
@@ -156,13 +151,11 @@ def profcfunc(filename):
|
||||
"s type filename and line number") % "design")
|
||||
|
||||
cume = 0
|
||||
for func in sorted(vfuncs.keys(),
|
||||
key=lambda f: vfuncs[f]['sec'],
|
||||
reverse=True):
|
||||
for func in sorted(vfuncs.keys(), key=lambda f: vfuncs[f]['sec'], reverse=True):
|
||||
cume += vfuncs[func]['sec']
|
||||
print(("%6.2f %9.2f %8.2f %10d %-" + str(design_width) + "s %s") %
|
||||
(vfuncs[func]['pct'], cume, vfuncs[func]['sec'],
|
||||
vfuncs[func]['calls'], vfuncs[func]['design'], func))
|
||||
(vfuncs[func]['pct'], cume, vfuncs[func]['sec'], vfuncs[func]['calls'],
|
||||
vfuncs[func]['design'], func))
|
||||
|
||||
|
||||
######################################################################
|
||||
@@ -180,18 +173,14 @@ in each Verilog block.
|
||||
|
||||
For documentation see
|
||||
https://verilator.org/guide/latest/exe_verilator_profcfunc.html""",
|
||||
epilog=
|
||||
"""Copyright 2002-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2002-2024 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""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('filename', help='input gprof output to process')
|
||||
|
||||
Args = parser.parse_args()
|
||||
|
||||
+5
-12
@@ -60,17 +60,14 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
||||
sudo apt-get install libgoogle-perftools-dev ||
|
||||
sudo apt-get install libgoogle-perftools-dev
|
||||
fi
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
|
||||
sudo apt-get install libsystemc libsystemc-dev ||
|
||||
sudo apt-get install libsystemc libsystemc-dev
|
||||
fi
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
|
||||
sudo apt-get install bear mold ||
|
||||
sudo apt-get install bear mold
|
||||
fi
|
||||
if [ "$COVERAGE" = 1 ]; then
|
||||
yes yes | sudo cpan -fi Parallel::Forker
|
||||
fi
|
||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
||||
brew update
|
||||
brew install ccache perl gperftools
|
||||
@@ -94,12 +91,12 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||
# libfl-dev needed for internal coverage's test runs
|
||||
sudo apt-get install gdb gtkwave lcov libfl-dev ccache jq z3 ||
|
||||
sudo apt-get install gdb gtkwave lcov libfl-dev ccache jq z3
|
||||
# Required for test_regress/t/t_dist_attributes.pl
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
|
||||
# Required for test_regress/t/t_dist_attributes.py
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
|
||||
sudo apt-get install python3-clang mold ||
|
||||
sudo apt-get install python3-clang mold
|
||||
fi
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ]; then
|
||||
if [ "$CI_RUNS_ON" = "ubuntu-20.04" ] || [ "$CI_RUNS_ON" = "ubuntu-22.04" ] || [ "$CI_RUNS_ON" = "ubuntu-24.04" ]; then
|
||||
sudo apt-get install libsystemc-dev ||
|
||||
sudo apt-get install libsystemc-dev
|
||||
fi
|
||||
@@ -114,10 +111,6 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||
fatal "Unknown os: '$CI_OS_NAME'"
|
||||
fi
|
||||
# Common installs
|
||||
if [ "$CI_RUNS_ON" != "ubuntu-14.04" ]; then
|
||||
CI_CPAN_REPO=https://cpan.org
|
||||
fi
|
||||
yes yes | sudo cpan -M $CI_CPAN_REPO -fi Parallel::Forker
|
||||
install-vcddiff
|
||||
# Workaround -fsanitize=address crash
|
||||
sudo sysctl -w vm.mmap_rnd_bits=28
|
||||
|
||||
+6
-5
@@ -33,6 +33,7 @@ elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
||||
else
|
||||
fatal "Unknown os: '$CI_OS_NAME'"
|
||||
fi
|
||||
NPROC=$(expr $NPROC '+' 1)
|
||||
|
||||
if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
||||
##############################################################################
|
||||
@@ -61,6 +62,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||
# Run tests
|
||||
|
||||
export VERILATOR_TEST_NO_CONTRIBUTORS=1 # Separate workflow check
|
||||
export VERILATOR_TEST_NO_LINT_PY=1 # Separate workflow check
|
||||
|
||||
if [ "$CI_OS_NAME" = "osx" ]; then
|
||||
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
|
||||
@@ -85,7 +87,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||
fi
|
||||
|
||||
# Run sanitize on Ubuntu 22.04 only
|
||||
[ "$CI_RUNS_ON" = 'ubuntu-22.04' ] && sanitize='--sanitize' || sanitize=''
|
||||
( [ "$CI_RUNS_ON" = 'ubuntu-22.04' ] || [ "$CI_RUNS_ON" = 'ubuntu-24.04' ] ) && sanitize='--sanitize' || sanitize=''
|
||||
|
||||
TEST_REGRESS=test_regress
|
||||
if [ "$CI_RELOC" == 1 ]; then
|
||||
@@ -192,13 +194,12 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
||||
fatal "Unknown test: $TESTS"
|
||||
;;
|
||||
esac
|
||||
|
||||
# To see load average (1 minute, 5 minute, 15 minute)
|
||||
uptime
|
||||
# 22.04: ccache -s -v
|
||||
ccache -s
|
||||
|
||||
# Upload coverage data
|
||||
if [[ $TESTS == coverage-* ]]; then
|
||||
bash <(cat ci/coverage-upload.sh) -f nodist/obj_dir/coverage/app_total.info
|
||||
fi
|
||||
else
|
||||
##############################################################################
|
||||
# Unknown build stage
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
Set-PSDebug -Trace 1
|
||||
|
||||
if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) {
|
||||
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
||||
cd winflexbison
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. --install-prefix $PWD/../../../.ccache
|
||||
cmake --build . --config Release -j 3
|
||||
cmake --install . --prefix $PWD/../../../.ccache
|
||||
cd ../..
|
||||
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
||||
cd winflexbison
|
||||
mkdir build
|
||||
cd build
|
||||
cmake .. --install-prefix $PWD/../../../.ccache
|
||||
cmake --build . --config Release -j 3
|
||||
cmake --install . --prefix $PWD/../../../.ccache
|
||||
cd ../..
|
||||
}
|
||||
|
||||
mkdir build
|
||||
|
||||
Executable
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -51,8 +51,6 @@ RUN apt-get update \
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
RUN cpan install -fi Parallel::Forker
|
||||
|
||||
RUN git clone https://github.com/veripool/vcddiff.git && \
|
||||
make -C vcddiff && \
|
||||
cp -p vcddiff/vcddiff /usr/local/bin/vcddiff && \
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
.. Copyright 2003-2024 by Wilson Snyder.
|
||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
.. _Verilator Build Docker Container:
|
||||
|
||||
Verilator Build Docker Container
|
||||
================================
|
||||
|
||||
|
||||
@@ -11,10 +11,11 @@ easily as a docker image, e.g.:
|
||||
|
||||
docker run -ti verilator/verilator:latest --version
|
||||
|
||||
This will install the container, run the latest Verilator and print
|
||||
This will pull the container from `docker hub
|
||||
<https://hub.docker.com/r/verilator/verilator>`_, run the latest Verilator and print
|
||||
Verilator's version.
|
||||
|
||||
Containers are automatically built for all released versions, so you may
|
||||
Containers are automatically built and pushed to docker hub for all released versions, so you may
|
||||
easily compare results across versions, e.g.:
|
||||
|
||||
::
|
||||
|
||||
+15
-17
@@ -1,3 +1,4 @@
|
||||
---
|
||||
# DESCRIPTION: codecov.io config
|
||||
#
|
||||
# Copyright 2020-2024 by Wilson Snyder. This program is free software; you
|
||||
@@ -8,31 +9,28 @@
|
||||
####################
|
||||
# Validate:
|
||||
# curl --data-binary @codecov.yml https://codecov.io/validate
|
||||
|
||||
#
|
||||
codecov:
|
||||
require_ci_to_pass: no
|
||||
|
||||
require_ci_to_pass: false
|
||||
coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "50...100"
|
||||
range: 50...100
|
||||
ignore:
|
||||
- "ci"
|
||||
- "docs"
|
||||
- "examples"
|
||||
- "include/gtkwave"
|
||||
- "include/vltstd"
|
||||
- "test_regress"
|
||||
|
||||
- "ci" #
|
||||
- "docs" #
|
||||
- "examples" #
|
||||
- "include/gtkwave" #
|
||||
- "include/vltstd" #
|
||||
- "test_regress" #
|
||||
parsers:
|
||||
gcov:
|
||||
branch_detection:
|
||||
conditional: yes
|
||||
loop: yes
|
||||
method: no
|
||||
macro: no
|
||||
|
||||
conditional: true
|
||||
loop: true
|
||||
method: false
|
||||
macro: false
|
||||
comment:
|
||||
layout: "reach,diff,flags,tree"
|
||||
behavior: default
|
||||
require_changes: yes
|
||||
require_changes: true
|
||||
|
||||
+60
-30
@@ -10,7 +10,7 @@
|
||||
# Then 'make maintainer-dist'
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[5.026 2024-06-15],
|
||||
AC_INIT([Verilator],[5.030 2024-10-27],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
|
||||
@@ -29,6 +29,9 @@ AC_DEFINE_UNQUOTED([PACKAGE_VERSION_STRING_CHAR],
|
||||
[Package version as a number])
|
||||
AC_SUBST(PACKAGE_VERSION_STRING_CHAR)
|
||||
|
||||
######################################################################
|
||||
## Arguments/flag checking
|
||||
|
||||
# Ignore automake flags passed by Ubuntu builds
|
||||
AC_ARG_ENABLE([dependency-tracking],
|
||||
[AS_HELP_STRING([--disable-dependency-tracking], [ignored])])
|
||||
@@ -156,6 +159,11 @@ AC_ARG_WITH([solver],
|
||||
AC_SUBST(CFG_WITH_SOLVER)
|
||||
AC_MSG_RESULT($CFG_WITH_SOLVER)
|
||||
|
||||
######################################################################
|
||||
## Compiler checks
|
||||
|
||||
AC_MSG_RESULT([compiler CXX inbound is set to... $CXX])
|
||||
|
||||
# Compiler flags (ensure they are not empty to avoid configure defaults)
|
||||
CFLAGS="$CFLAGS "
|
||||
CPPFLAGS="$CPPFLAGS "
|
||||
@@ -182,24 +190,26 @@ if test "x$AR" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "ar" in your PATH, please install it])
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(PERL,perl)
|
||||
AC_CHECK_PROG(PERL,perl,perl)
|
||||
if test "x$PERL" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(PYTHON3,python3)
|
||||
AC_CHECK_PROG(PYTHON3,python3,python3)
|
||||
if test "x$PYTHON3" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "python3" in your PATH, please install it])
|
||||
fi
|
||||
python3_version=$($PYTHON3 --version | head -1)
|
||||
AC_MSG_RESULT([$PYTHON3 --version = $python3_version])
|
||||
|
||||
AC_PATH_PROG(LEX,flex)
|
||||
AC_CHECK_PROG(LEX,flex,flex)
|
||||
if test "x$LEX" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
|
||||
fi
|
||||
flex_version=$($LEX --version | head -1)
|
||||
AC_MSG_RESULT([$LEX --version = $flex_version])
|
||||
|
||||
AC_PATH_PROG(YACC,bison)
|
||||
AC_CHECK_PROG(YACC,bison,bison)
|
||||
if test "x$YACC" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
||||
fi
|
||||
@@ -288,6 +298,43 @@ AC_DEFUN([_MY_CXX_CHECK_OPT],
|
||||
_MY_CXX_CHECK_IFELSE($2, $1="$$1 $2")
|
||||
])
|
||||
|
||||
AC_DEFUN([_MY_CXX_CHECK_CORO_SET],
|
||||
[# _MY_CXX_CHECK_CORO_SET(variable,option)
|
||||
# Check if compiler supports coroutines with specific option. If it does,
|
||||
# set variable to option, only if not previously set.
|
||||
# Define HAVE_COROUTINES if supported.
|
||||
if test "$$1" = ""; then
|
||||
if test "$2" != ""; then
|
||||
_my_msg_opt=" with $2"
|
||||
else
|
||||
_my_msg_opt=""
|
||||
fi
|
||||
AC_MSG_CHECKING([whether coroutines are supported by $CXX$_my_msg_opt])
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $2"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([
|
||||
#if defined(__clang__) && !defined(__cpp_impl_coroutine)
|
||||
#define __cpp_impl_coroutine 1
|
||||
#endif
|
||||
#include <coroutine>
|
||||
],[[std::coroutine_handle<> h;]])],
|
||||
[_my_result=yes],
|
||||
[AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM(
|
||||
[#include <experimental/coroutine>],
|
||||
[[std::experimental::coroutine_handle<> h;]])],
|
||||
[_my_result=yes],
|
||||
[_my_result=no])])
|
||||
AC_MSG_RESULT($_my_result)
|
||||
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||
if test "$_my_result" = "yes" ; then
|
||||
$1="$2"
|
||||
AC_DEFINE([HAVE_COROUTINES],[1],[Defined if coroutines are supported by $CXX])
|
||||
fi
|
||||
fi
|
||||
])
|
||||
|
||||
AC_DEFUN([_MY_LDLIBS_CHECK_FLAG],
|
||||
[# _MY_LDLIBS_CHECK_FLAG(flag) -- Check if linker supports specific options
|
||||
# Set $_my_result appropriately
|
||||
@@ -373,32 +420,12 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wthread-safety)
|
||||
AC_SUBST(CFG_CXXFLAGS_WEXTRA)
|
||||
|
||||
# Flags for coroutine support for dynamic scheduling
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts -Wno-deprecated-experimental-coroutine)
|
||||
_MY_CXX_CHECK_CORO_SET(CFG_CXXFLAGS_COROUTINES, "")
|
||||
_MY_CXX_CHECK_CORO_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts)
|
||||
_MY_CXX_CHECK_CORO_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines)
|
||||
_MY_CXX_CHECK_CORO_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts -Wno-deprecated-experimental-coroutine)
|
||||
_MY_CXX_CHECK_CORO_SET(CFG_CXXFLAGS_COROUTINES,-std=gnu++20)
|
||||
AC_SUBST(CFG_CXXFLAGS_COROUTINES)
|
||||
|
||||
# HAVE_COROUTINES
|
||||
# Check if coroutines are supported at all
|
||||
AC_MSG_CHECKING([whether coroutines are supported by $CXX])
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_COROUTINES"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([
|
||||
#ifdef __clang__
|
||||
#define __cpp_impl_coroutine 1
|
||||
#endif
|
||||
#include <coroutine>
|
||||
],[[]])],
|
||||
[_my_result=yes
|
||||
AC_DEFINE([HAVE_COROUTINES],[1],[Defined if coroutines are supported by $CXX])],
|
||||
[AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <experimental/coroutine>],[[]])],
|
||||
[_my_result=yes
|
||||
AC_DEFINE([HAVE_COROUTINES],[1],[Defined if coroutines are supported by $CXX])],
|
||||
[_my_result=no])])
|
||||
AC_MSG_RESULT($_my_result)
|
||||
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||
AC_SUBST(HAVE_COROUTINES)
|
||||
|
||||
# Flags for compiling Verilator internals including parser always
|
||||
@@ -606,6 +633,9 @@ AC_SUBST(HAVE_SYSTEMC)
|
||||
|
||||
# Checks for system services
|
||||
|
||||
######################################################################
|
||||
## Output
|
||||
|
||||
# Other install directories
|
||||
pkgdatadir=${datadir}/verilator
|
||||
AC_SUBST(pkgdatadir)
|
||||
|
||||
@@ -7,6 +7,7 @@ Adam Bagley
|
||||
Adrian Sampson
|
||||
Adrien Le Masle
|
||||
Ahmed El-Mahmoudy
|
||||
Aidan McNay
|
||||
Aleksander Kiryk
|
||||
Alex Chadwick
|
||||
Alex Solomatnikov
|
||||
@@ -25,6 +26,7 @@ Aylon Chaim Porat
|
||||
Bartłomiej Chmiel
|
||||
Cameron Kirk
|
||||
Chih-Mao Chen
|
||||
Chris Bachhuber
|
||||
Chris Randall
|
||||
Christopher Taylor
|
||||
Chuxuan Wang
|
||||
@@ -43,9 +45,12 @@ Drew Ranck
|
||||
Drew Taussig
|
||||
Driss Hafdi
|
||||
Edgar E. Iglesias
|
||||
Eric Müller
|
||||
Eric Rippey
|
||||
Ethan Sifferman
|
||||
Eyck Jentzsch
|
||||
Furqan Nadir
|
||||
Fabian Keßler
|
||||
Fan Shupei
|
||||
february cozzocrea
|
||||
Felix Neumärker
|
||||
@@ -63,6 +68,7 @@ Graham Rushton
|
||||
Guokai Chen
|
||||
Gus Smith
|
||||
Gustav Svensk
|
||||
Han Qi
|
||||
Harald Heckmann
|
||||
Hennadii Chernyshchyk
|
||||
Howard Su
|
||||
@@ -76,6 +82,7 @@ Iru Cai
|
||||
Ivan Vnučec
|
||||
Iztok Jeras
|
||||
Jake Merdich
|
||||
James Bailey
|
||||
James Hanlon
|
||||
James Hutchinson
|
||||
James Pallister
|
||||
@@ -118,8 +125,11 @@ Kritik Bhimani
|
||||
Krzysztof Bieganski
|
||||
Krzysztof Boronski
|
||||
Krzysztof Boroński
|
||||
Krzysztof Obłonczek
|
||||
Kuba Ober
|
||||
Larry Doolittle
|
||||
Liam Braun
|
||||
Luca Colagrande
|
||||
Ludwig Rogiers
|
||||
Lukasz Dalek
|
||||
Maarten De Braekeleer
|
||||
@@ -143,6 +153,7 @@ Mladen Slijepcevic
|
||||
Morten Borup Petersen
|
||||
Mostafa Gamal
|
||||
Nandu Raj
|
||||
Nathan Graybeal
|
||||
Nathan Kohagen
|
||||
Nathan Myers
|
||||
Nolan Poe
|
||||
@@ -157,6 +168,7 @@ Pengcheng Xu
|
||||
Peter Debacker
|
||||
Peter Horvath
|
||||
Peter Monsson
|
||||
Philip Axer
|
||||
Philipp Wagner
|
||||
Pierre-Henri Horrein
|
||||
Pieter Kapsenberg
|
||||
@@ -166,15 +178,18 @@ Quentin Corradi
|
||||
Rafal Kapuscik
|
||||
Rasfunk
|
||||
Raynard Qiao
|
||||
Ricardo Barbedo
|
||||
Richard Myers
|
||||
Risto Pejašinović
|
||||
Robert Balas
|
||||
Rupert Swarbrick
|
||||
Ryan Ziegler
|
||||
Ryszard Rozak
|
||||
Samuel Riedel
|
||||
Sean Cross
|
||||
Sebastien Van Cauwenberghe
|
||||
Sergi Granell
|
||||
Seth Pellegrino
|
||||
Srinivasan Venkataramanan
|
||||
Stefan Wallentowitz
|
||||
Stephen Henry
|
||||
@@ -194,6 +209,7 @@ Tudor Timi
|
||||
Tymoteusz Blazejczyk
|
||||
Udi Finkelstein
|
||||
Unai Martinez-Corral
|
||||
Udaya Raj Subedi
|
||||
Valentin Atepalikhin
|
||||
Varun Koyyalagunta
|
||||
Vassilis Papaefstathiou
|
||||
@@ -204,6 +220,8 @@ William D. Jones
|
||||
Wilson Snyder
|
||||
Xi Zhang
|
||||
Yan Xu
|
||||
Yangyu Chen
|
||||
Yilou Wang
|
||||
Yinan Xu
|
||||
Yoda Lee
|
||||
Yossi Nivin
|
||||
@@ -215,3 +233,4 @@ Zhanglei Wang
|
||||
Zhou Shen
|
||||
Zixi Li
|
||||
أحمد المحمودي
|
||||
404allen404
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ SPHINXBUILD ?= sphinx-build
|
||||
SOURCEDIR = guide
|
||||
BUILDDIR = _build
|
||||
|
||||
SPHINXOPTS ?= -c guide
|
||||
SPHINXOPTS ?= -c guide -j 4
|
||||
ifneq ($(VERILATOR_ANALYTICS_ID),)
|
||||
SPHINXOPTS += -D html_theme_options.analytics_id=$(VERILATOR_ANALYTICS_ID)
|
||||
endif
|
||||
|
||||
@@ -23,9 +23,7 @@ class VlSphinxExtract:
|
||||
outname = match.group(1)
|
||||
print("Writing %s" % outname)
|
||||
fhw = open(outname, "w", encoding="utf8") # pylint: disable=consider-using-with
|
||||
fhw.write(
|
||||
".. comment: generated by vl_sphinx_extract from " +
|
||||
filename + "\n")
|
||||
fhw.write(".. comment: generated by vl_sphinx_extract from " + filename + "\n")
|
||||
fhw.write(".. code-block::\n")
|
||||
elif re.match(r'^[=a-zA-Z0-9_]', line):
|
||||
fhw = None
|
||||
@@ -39,18 +37,14 @@ parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""Read a file and extract documentation data.""",
|
||||
epilog=
|
||||
""" Copyright 2021-2024 by Wilson Snyder. This package is free software;
|
||||
epilog=""" Copyright 2021-2024 by Wilson Snyder. This package 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""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('path', help='path to extract from')
|
||||
Args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ class VlSphinxFix:
|
||||
if os.path.isdir(path):
|
||||
for basefile in os.listdir(path):
|
||||
file = os.path.join(path, basefile)
|
||||
if ((basefile != ".") and (basefile != "..")
|
||||
and basefile not in self.SkipBasenames
|
||||
if ((basefile != ".") and (basefile != "..") and basefile not in self.SkipBasenames
|
||||
and not os.path.islink(file)):
|
||||
self.process(file)
|
||||
elif re.search(r'\.(html|tex)$', path):
|
||||
@@ -54,18 +53,14 @@ parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""Post-process Sphinx HTML.""",
|
||||
epilog=
|
||||
""" Copyright 2021-2024 by Wilson Snyder. This package is free software;
|
||||
epilog=""" Copyright 2021-2024 by Wilson Snyder. This package 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""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('path', help='path to edit')
|
||||
Args = parser.parse_args()
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
.. comment: generated by t_lint_multidriven_bad
|
||||
.. code-block::
|
||||
|
||||
%Warning-MULTIDRIVEN: example.v:1:22 Signal has multiple driving blocks with different clocking: 't.mem'
|
||||
%Warning-MULTIDRIVEN: example.v:1:22 Signal has multiple driving blocks with different clocking: 'out2'
|
||||
example.v:1:7 ... Location of first driving block
|
||||
example.v:1:7 ... Location of other driving block
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
.. comment: generated by t_lint_pinmissing_bad
|
||||
.. code-block:: sv
|
||||
:linenos:
|
||||
:emphasize-lines: 2
|
||||
|
||||
module t;
|
||||
sub sub(); // <--- Warning
|
||||
endmodule
|
||||
module sub
|
||||
(output port);
|
||||
endmodule
|
||||
@@ -0,0 +1,4 @@
|
||||
.. comment: generated by t_lint_pinmissing_bad
|
||||
.. code-block::
|
||||
|
||||
%Warning-PINMISSING: example.v:1:8 Cell has missing pin: 'port'
|
||||
@@ -0,0 +1,11 @@
|
||||
.. comment: generated by t_lint_pkgnodecl_bad
|
||||
.. code-block:: sv
|
||||
:linenos:
|
||||
:emphasize-lines: 2
|
||||
|
||||
module t;
|
||||
initial Pkg::hello(); //<--- Warning
|
||||
endmodule
|
||||
package Pkg;
|
||||
function void hello(); endfunction
|
||||
endpackage
|
||||
@@ -0,0 +1,4 @@
|
||||
.. comment: generated by t_lint_pkgnodecl_bad
|
||||
.. code-block::
|
||||
|
||||
%Error-PKGNODECL: example.v:1:12 Package/class 'Pkg' not found, and needs to be predeclared (IEEE 1800-2023 26.3)
|
||||
+2
-4
@@ -23,8 +23,7 @@ def get_vlt_version():
|
||||
filename = "../../Makefile"
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
for line in fh:
|
||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)",
|
||||
line)
|
||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)", line)
|
||||
if match:
|
||||
return match.group(1), match.group(2)
|
||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +devel", line)
|
||||
@@ -75,8 +74,7 @@ extensions = []
|
||||
# directories to ignore when looking for source files.
|
||||
# This pattern also affects html_static_path and html_extra_path.
|
||||
exclude_patterns = [
|
||||
'_build', 'Thumbs.db', '.DS_Store', 'internals.rst', 'xml.rst', 'gen/ex_*',
|
||||
'CONTRIBUTING.rst'
|
||||
'_build', 'Thumbs.db', '.DS_Store', 'internals.rst', 'xml.rst', 'gen/ex_*', 'CONTRIBUTING.rst'
|
||||
]
|
||||
|
||||
# Warn about refs
|
||||
|
||||
+29
-11
@@ -23,24 +23,24 @@ Next, try the :vlopt:`--debug` option. This will enable additional
|
||||
internal assertions, and may help identify the problem.
|
||||
|
||||
Finally, reduce your code to the smallest possible routine that exhibits
|
||||
the bug. Even better, create a test in the :file:`test_regress/t`
|
||||
directory, as follows:
|
||||
the bug (see: :ref:`Minimizing bug-inducing code`). Even better, create
|
||||
a test in the :file:`test_regress/t` directory, as follows:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd test_regress
|
||||
cp -p t/t_EXAMPLE.pl t/t_BUG.pl
|
||||
cp -p t/t_EXAMPLE.py t/t_BUG.py
|
||||
cp -p t/t_EXAMPLE.v t/t_BUG.v
|
||||
|
||||
There are many hints on how to write a good test in the
|
||||
:file:`test_regress/driver.pl` documentation which can be seen by running:
|
||||
:file:`test_regress/driver.py` documentation which can be seen by running:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
cd $VERILATOR_ROOT # Need the original distribution kit
|
||||
test_regress/driver.pl --help
|
||||
test_regress/driver.py --help
|
||||
|
||||
Edit :file:`t/t_BUG.pl` to suit your example; you can do anything you want
|
||||
Edit :file:`t/t_BUG.py` to suit your example; you can do anything you want
|
||||
in the Verilog code there; just make sure it retains the single clk input
|
||||
and no outputs. Now, the following should fail:
|
||||
|
||||
@@ -48,20 +48,38 @@ and no outputs. Now, the following should fail:
|
||||
|
||||
cd $VERILATOR_ROOT # Need the original distribution kit
|
||||
cd test_regress
|
||||
t/t_BUG.pl # Run on Verilator
|
||||
t/t_BUG.pl --debug # Run on Verilator, passing --debug to Verilator
|
||||
t/t_BUG.pl --vcs # Run on VCS simulator
|
||||
t/t_BUG.pl --nc|--iv|--ghdl # Likewise on other simulators
|
||||
t/t_BUG.py # Run on Verilator
|
||||
t/t_BUG.py --debug # Run on Verilator, passing --debug to Verilator
|
||||
t/t_BUG.py --vcs # Run on VCS simulator
|
||||
t/t_BUG.py --nc|--iv|--ghdl # Likewise on other simulators
|
||||
|
||||
The test driver accepts a number of options, many of which mirror the main
|
||||
Verilator options. For example the previous test could have been run with
|
||||
debugging enabled. The full set of test options can be seen by running
|
||||
:command:`driver.pl --help` as shown above.
|
||||
:command:`driver.py --help` as shown above.
|
||||
|
||||
Finally, report the bug at `Verilator Issues
|
||||
<https://verilator.org/issues>`_. The bug will become publicly visible; if
|
||||
this is unacceptable, mail the bug report to ``[email protected]``.
|
||||
|
||||
.. _Minimizing bug-inducing code:
|
||||
|
||||
Minimizing bug-inducing code
|
||||
============================
|
||||
|
||||
In some cases, the part of the code that causes the bug is clearly visible
|
||||
and the design can be easily manually reduced. In other cases, the bug is
|
||||
caused by a complex interaction of many parts of the design, and it is not
|
||||
clear which parts are necessary to reproduce the bug. In these cases, an
|
||||
Open Source tool called `sv-bugpoint
|
||||
<https://github.com/antmicro/sv-bugpoint>_` can be used to automatically
|
||||
reduce a SystemVerilog design to the smallest possible reproducer.
|
||||
It can be used to automatically reduce a design with hundreds of thousands of
|
||||
lines to a minimal test case while preserving the bug-inducing behavior.
|
||||
|
||||
Please refer to the `README
|
||||
<https://github.com/antmicro/sv-bugpoint/blob/main/README.md>`_ file for more
|
||||
information on how to use `sv-bugpoint`.
|
||||
|
||||
.. Contributing
|
||||
.. ============
|
||||
|
||||
@@ -12,7 +12,7 @@ C++14 compiler support
|
||||
Verilated models with --no-timing.
|
||||
|
||||
Verilator will require C++20 or newer compilers for both compiling
|
||||
Verilator and compiling all Verilated models no sooner than January 2025.
|
||||
Verilator and compiling all Verilated models no sooner than May 2025.
|
||||
|
||||
XML output
|
||||
Verilator currently supports XML parser output (enabled with `--xml-only`).
|
||||
|
||||
@@ -28,6 +28,7 @@ Now, let's create an example Verilog, and SystemC wrapper file:
|
||||
|
||||
cat >sc_main.cpp <<'EOF'
|
||||
#include "Vour.h"
|
||||
using namespace sc_core;
|
||||
int sc_main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
sc_clock clk{"clk", 10, SC_NS, 0.5, 3, SC_NS, true};
|
||||
|
||||
@@ -40,8 +40,8 @@ Summary:
|
||||
.. option:: +verilator+error+limit+<value>
|
||||
|
||||
Set number of non-fatal errors (e.g. assertion failures) before exiting
|
||||
simulation runtime. Also affects number of $stop calls needed before
|
||||
exit. Defaults to 1.
|
||||
simulation runtime. Also affects number of `$stop` calls needed before
|
||||
exit. Does not affect `$fatal`. Defaults to 1.
|
||||
|
||||
.. option:: +verilator+help
|
||||
|
||||
|
||||
@@ -222,6 +222,13 @@ Summary:
|
||||
expressions into sub-expressions to avoid error C1009, and breaking
|
||||
deep blocks into functions to avoid error C1061.
|
||||
|
||||
.. option:: --compiler-include <header-path>
|
||||
|
||||
Specifies additional headers to be included in the final PCH header.
|
||||
It is required to add them to this header, due to compilers'
|
||||
limitation that allow only one precompiled header per compilation.
|
||||
Use this instead of ::vlopt:`-CFLAGS` with `-include <header-path>`.
|
||||
|
||||
.. option:: --converge-limit <loops>
|
||||
|
||||
Rarely needed. Specifies the maximum number of runtime iterations
|
||||
@@ -476,6 +483,12 @@ Summary:
|
||||
See also :vlopt:`--dump-defines`, :vlopt:`-P`, and
|
||||
:vlopt:`--pp-comments` options.
|
||||
|
||||
.. option:: --emit-accessors
|
||||
|
||||
Emit getter and setter methods for each top-level signal in the
|
||||
model top class. Signals are still available as public members,
|
||||
but with the `__Vm_sig_` prefix.
|
||||
|
||||
.. option:: --error-limit <value>
|
||||
|
||||
After this number of errors are encountered during Verilator run, exit.
|
||||
@@ -710,6 +723,13 @@ Summary:
|
||||
:option:`/*verilator&32;hier_block*/` metacomment is ignored. See
|
||||
:ref:`Hierarchical Verilation`.
|
||||
|
||||
.. option:: --hierarchical-params-file <filename>
|
||||
|
||||
Internal flag inserted used during :vlopt:`--hierarchical`; specifies
|
||||
name of hierarchical parameters file for deparametrized modules with
|
||||
:option:`/*verilator&32;hier_block*/` metacomment. See
|
||||
:ref:`Hierarchical Verilation`.
|
||||
|
||||
.. option:: -I<dir>
|
||||
|
||||
See :vlopt:`-y`.
|
||||
@@ -938,6 +958,22 @@ Summary:
|
||||
delayed assignments. This option should only be used when suggested by
|
||||
the developers.
|
||||
|
||||
.. option:: --output-groups <numfiles>
|
||||
|
||||
Enables concatenating the output .cpp files into the given number of
|
||||
effective output .cpp files. This is useful if the compiler startup
|
||||
overhead from compiling many small files becomes unacceptable,
|
||||
which can happen in designs making extensive use of SystemVerilog classes,
|
||||
templates or generate blocks.
|
||||
|
||||
Using :vlopt:`--output-groups` can adversely impact caching and stability
|
||||
(as in reproducibility) of compiled code. Compilation of larger .cpp
|
||||
files also has higher memory requirements. Too low values might result in
|
||||
swap thrashing with large designs, high values give no benefits. The
|
||||
value should range from 2 to 20 for small to medium designs.
|
||||
|
||||
Default is zero, which disables this feature.
|
||||
|
||||
.. option:: --output-split <statements>
|
||||
|
||||
Enables splitting the output .cpp files into multiple outputs. When a
|
||||
@@ -1004,6 +1040,10 @@ Summary:
|
||||
:vlopt:`--pins-sc-biguint` combination, it results in sc_uint being used
|
||||
between 2 and 64 and sc_biguint being used between 65 and 512.
|
||||
|
||||
.. option:: --pins-sc-uint-bool
|
||||
|
||||
Specifies SystemC inputs/outputs one bit wide should use sc_uint<1>.
|
||||
|
||||
.. option:: --pins-sc-biguint
|
||||
|
||||
Specifies SystemC inputs/outputs greater than 65 bits wide should use
|
||||
@@ -1885,8 +1925,12 @@ Configuration Files
|
||||
|
||||
In addition to the command line, warnings and other features for the
|
||||
:command:`verilator` command may be controlled with configuration files,
|
||||
typically named with the .vlt extension (what makes it a configuration file
|
||||
is the :option:`\`verilator_config` directive). An example:
|
||||
typically named with the `.vlt` extension (what makes it a configuration
|
||||
file is the :option:`\`verilator_config` directive). These files, when
|
||||
named `.vlt`, are read before source code files; if this behavior is
|
||||
undesired, name the config file with a `.v` suffix.
|
||||
|
||||
An example:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
@@ -1979,6 +2023,13 @@ The grammar of configuration commands is as follows:
|
||||
that the setting is ignored unless the :vlopt:`--hierarchical` option is
|
||||
specified. See :ref:`Hierarchical Verilation`.
|
||||
|
||||
.. option:: hier_params -module "<modulename>"
|
||||
|
||||
Specifies that the module contains parameters a :vlopt:`--hierarchical` block. This option
|
||||
is used internally to specify parameters for deparametrized hier block instances.
|
||||
This option should not be used directly.
|
||||
See :ref:`Hierarchical Verilation`.
|
||||
|
||||
.. option:: inline -module "<modulename>"
|
||||
|
||||
Specifies the module may be inlined into any modules that use this
|
||||
|
||||
@@ -58,32 +58,36 @@ to read multiple inputs. If no data file is specified, by default,
|
||||
Specifies the directory name to which source files with annotated coverage
|
||||
data should be written.
|
||||
|
||||
Converting from the Verilator coverage data format to the info format is
|
||||
lossy; the info will have all forms of coverage merged line coverage, and
|
||||
if there are multiple coverage points on a single line they will merge.
|
||||
The minimum coverage across all merged points will be used to report
|
||||
coverage of the line.
|
||||
Points are children of each line coverage- branches or toggle points.
|
||||
When point counts are aggregated into a line, the minimum and maximum counts
|
||||
are used to determine the status of the line (complete, partial, failing)
|
||||
The count is equal to the maximum of the points.
|
||||
|
||||
Coverage data is annotated at the beginning of the line and is formatted
|
||||
as a special character followed by the number of coverage hits. The special
|
||||
characters " ,%,+,-" indicate summary of the coverage, and allow use of grep
|
||||
characters " ,%,~,+,-" indicate summary of the coverage, and allow use of grep
|
||||
to filter the report.
|
||||
|
||||
* " " (whitespace) indicates that all points on the line are above the coverage limit.
|
||||
* "%" indicates at least one point on the line was below the coverage limit.
|
||||
* "+" coverage point was at or above the limit. Only used with :option:`--annotate-points`.
|
||||
* "-" coverage point was below the limit. Only used with :option:`--annotate-points`.
|
||||
* " " (whitespace) indicates that all points on the line are above the coverage min.
|
||||
* "%" indicates that all points on the line are below the coverage min.
|
||||
* "~" indicates that some points on the line are above the coverage min and some are below.
|
||||
* "+" coverage point was at or above the min. Only used with :option:`--annotate-points`.
|
||||
* "-" coverage point was below the min. Only used with :option:`--annotate-points`.
|
||||
|
||||
.. code-block::
|
||||
|
||||
100000 input logic a; // Begins with whitespace, because
|
||||
// number of hits (100000) is above the limit.
|
||||
+100000 point: comment=a // Begins with +, because
|
||||
// number of hits (100000) is above the limit.
|
||||
%000000 input logic b; // Begins with %, because
|
||||
// number of hits (0) is below the limit.
|
||||
-000000 point: comment=b // Begins with -, because
|
||||
// number of hits (0) is below the limit.
|
||||
100000 input logic a; // Begins with whitespace, because
|
||||
// number of hits (100000) is above the min.
|
||||
+100000 point: comment=a // Begins with +, because
|
||||
// number of hits (100000) is above the min.
|
||||
%000000 input logic b; // Begins with %, because
|
||||
// number of hits (0) is below the min.
|
||||
-000000 point: comment=b // Begins with -, because
|
||||
// number of hits (0) is below the min.
|
||||
~000010 if (cyc!=0) begin // Begins with ~, because
|
||||
// branches are below and above the min.
|
||||
+000010 point: comment=if // The if branch is above the min.
|
||||
-000000 point: comment=else // The else branch is below the min.
|
||||
|
||||
.. option:: --annotate-all
|
||||
|
||||
@@ -154,10 +158,7 @@ generated from random test runs) into one master coverage file.
|
||||
Specifies the aggregate coverage results, summed across all the files,
|
||||
should be written to the given filename in :command:`lcov` .info format.
|
||||
This may be used to feed into :command:`lcov` to aggregate or generate
|
||||
reports.
|
||||
|
||||
Converting from the Verilator coverage data format to the info format is
|
||||
lossy; the info will have all forms of coverage merged line coverage, and
|
||||
if there are multiple coverage points on a single line they will merge.
|
||||
The minimum coverage across all merged points will be used to report
|
||||
coverage of the line.
|
||||
reports. This format lacks the comments for cover points that the
|
||||
verilator_coverage format has. It can be used with :command:`genhtml`
|
||||
to generate an HTML report. :command:`genhtml --branch-coverage` will
|
||||
also display the branch coverage, analogous to :option:`--annotate-points`
|
||||
|
||||
+5
-3
@@ -259,9 +259,11 @@ How do I view waveforms (aka dumps or traces)?
|
||||
""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Verilator creates standard VCD (Value Change Dump) and FST files. VCD
|
||||
files are viewable with the open-source GTKWave (recommended), or Dinotrace
|
||||
(legacy) programs, or any of the many closed-source offerings; FST is
|
||||
supported only by GTKWave.
|
||||
files are viewable with the open-source
|
||||
`GTKWave <http://gtkwave.sourceforge.net/>`_,
|
||||
`Surfer <https://surfer-project.org/>`_, Dinotrace (legacy), or any of the
|
||||
many closed-source viewer offerings; FST is supported only by GTKWave and
|
||||
Surfer.
|
||||
|
||||
|
||||
How do I speed up writing large waveform (trace) files?
|
||||
|
||||
+12
-10
@@ -48,12 +48,6 @@ For --cc/--sc, it creates:
|
||||
- Make include file for compiling (from --make gmake)
|
||||
* - *{prefix}*\ _classes.mk
|
||||
- Make include file with class names (from --make gmake)
|
||||
* - *{prefix}*\ _hier.mk
|
||||
- Make file for hierarchy blocks (from --make gmake)
|
||||
* - *{prefix}*\ __hierMkArgs.f
|
||||
- Arguments for hierarchical Verilation (from --make gmake)
|
||||
* - *{prefix}*\ __hierCMakeArgs.f
|
||||
- Arguments for hierarchical Verilation (from --make cmake)
|
||||
* - *{prefix}*\ .h
|
||||
- Model header
|
||||
* - *{prefix}*\ .cpp
|
||||
@@ -95,16 +89,24 @@ For --cc/--sc, it creates:
|
||||
* - *{prefix}{each_verilog_module}{__DepSet_hash__n}*\ .cpp
|
||||
- Additional lower C++ files (hashed to reduce build times)
|
||||
|
||||
For --hierarchy mode, it creates:
|
||||
For --hierarchical mode, it creates:
|
||||
|
||||
.. list-table::
|
||||
|
||||
* - V\ *{hier_block}*\ /
|
||||
- Directory to Verilate each hierarchy block (from --hierarchy)
|
||||
- Directory to Verilate each hierarchical block (from --hierarchical)
|
||||
* - *{prefix}*\ __hierVer.d
|
||||
- Make dependencies of the top module (from --hierarchy)
|
||||
- Make dependencies of the top module (from --hierarchical)
|
||||
* - *{prefix}*\ _hier.mk
|
||||
- Make file for hierarchical blocks (from --make gmake)
|
||||
* - *{prefix}*\ __hierCMakeArgs.f
|
||||
- Arguments for hierarchical Verilation (from --make cmake)
|
||||
* - *{prefix}*\ __hierMkArgs.f
|
||||
- Arguments for hierarchical Verilation (from --make gmake)
|
||||
* - *{prefix}*\ __hierParameters.v
|
||||
- Module parameters for hierarchical blocks
|
||||
* - *{prefix}*\ __hier.dir
|
||||
- Directory to store .dot, .vpp, .tree of top module (from --hierarchy)
|
||||
- Directory to store .dot, .vpp, .tree of top module (from --hierarchical)
|
||||
|
||||
In specific debug and other modes, it also creates:
|
||||
|
||||
|
||||
+38
-19
@@ -19,13 +19,33 @@ started. (Note packages are unlikely to have the most recent version, so
|
||||
:ref:`Git Install` might be a better alternative.) To install as a
|
||||
package:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
apt-get install verilator # On Ubuntu
|
||||
|
||||
For other distributions, refer to `Repology Verilator Distro Packages
|
||||
<https://repology.org/project/verilator>`__.
|
||||
|
||||
.. _pre-commit Quick Install:
|
||||
|
||||
pre-commit Quick Install
|
||||
=============================
|
||||
|
||||
You can use Verilator's `pre-commit <https://pre-commit.com/>`__ hook to
|
||||
lint your code before committing it. It encapsulates the :ref:`Verilator
|
||||
Build Docker Container`, so you need docker on your system to use it. The
|
||||
verilator image will be downloaded automatically.
|
||||
|
||||
To use the hook, add the following entry to your :code:`.pre-commit-config.yaml`:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/verilator/verilator
|
||||
rev: v5.026 # or later
|
||||
hooks:
|
||||
- id: verilator
|
||||
|
||||
.. _Git Install:
|
||||
|
||||
Git Quick Install
|
||||
@@ -36,7 +56,7 @@ options and details, see :ref:`Detailed Build Instructions` below.
|
||||
|
||||
In brief, to install from git:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
# Prerequisites:
|
||||
#sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache
|
||||
@@ -89,7 +109,7 @@ Install Prerequisites
|
||||
|
||||
To build or run Verilator, you need these standard packages:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install git help2man perl python3 make
|
||||
sudo apt-get install g++ # Alternatively, clang
|
||||
@@ -101,7 +121,7 @@ To build or run Verilator, you need these standard packages:
|
||||
To build or run Verilator, the following are optional but should be installed
|
||||
for good performance:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install ccache # If present at build, needed for run
|
||||
sudo apt-get install mold # If present at build, needed for run
|
||||
@@ -110,27 +130,26 @@ for good performance:
|
||||
The following is optional but is recommended for nicely rendered command line
|
||||
help when running Verilator:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install perl-doc
|
||||
|
||||
To build Verilator you will need to install these packages; these do not
|
||||
need to be present to run Verilator:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install git autoconf flex bison
|
||||
|
||||
Those developing Verilator itself may also want these (see internals.rst):
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
sudo apt-get install clang clang-format-14 cmake gdb gprof graphviz lcov
|
||||
sudo apt-get install python3-clang yapf3 bear jq
|
||||
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||
sudo pip3 install git+https://github.com/antmicro/astsee.git
|
||||
cpan install Pod::Perldoc
|
||||
cpan install Parallel::Forker
|
||||
|
||||
|
||||
Install SystemC
|
||||
@@ -171,14 +190,14 @@ Obtain Sources
|
||||
Get the sources from the git repository: (You need to do this only once,
|
||||
ever.)
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
git clone https://github.com/verilator/verilator # Only first time
|
||||
## Note the URL above is not a page you can see with a browser; it's for git only
|
||||
|
||||
Enter the checkout and determine what version/branch to use:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
cd verilator
|
||||
git pull # Make sure we're up-to-date
|
||||
@@ -193,7 +212,7 @@ Auto Configure
|
||||
|
||||
Create the configuration script:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
autoconf # Create ./configure script
|
||||
|
||||
@@ -219,7 +238,7 @@ directory (don't run ``make install``). This allows the easiest
|
||||
experimentation and upgrading, and allows many versions of Verilator to
|
||||
co-exist on a system.
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
export VERILATOR_ROOT=`pwd` # if your shell is bash
|
||||
setenv VERILATOR_ROOT `pwd` # if your shell is csh
|
||||
@@ -241,7 +260,7 @@ that may support multiple versions of every tool. Tell configure the
|
||||
eventual destination directory name. We recommend that the destination
|
||||
location include the Verilator version name:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
@@ -253,7 +272,7 @@ the ``bin`` directory to your ``PATH``. Or, if you use `modulecmd
|
||||
<http://modules.sourceforge.net/>`__, you'll want a module file like the
|
||||
following:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
set install_root /CAD_DISK/verilator/{version-number-used-above}
|
||||
unsetenv VERILATOR_ROOT
|
||||
@@ -268,7 +287,7 @@ following:
|
||||
The final option is to eventually install Verilator globally, using
|
||||
configure's default system paths:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
@@ -285,7 +304,7 @@ The command to configure the package was described in the previous step.
|
||||
Developers should configure to have more complete developer tests.
|
||||
Additional packages may be required for these tests.
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
export VERILATOR_AUTHOR_SITE=1 # Put in your .bashrc
|
||||
./configure --enable-longtests ...above options...
|
||||
@@ -296,7 +315,7 @@ Compile
|
||||
|
||||
Compile Verilator:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
make -j `nproc` # Or if error on `nproc`, the number of CPUs in system
|
||||
|
||||
@@ -306,7 +325,7 @@ Test
|
||||
|
||||
Check the compilation by running self-tests:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
make test
|
||||
|
||||
@@ -318,7 +337,7 @@ If you used any install option other than the `1. Run-in-Place from
|
||||
VERILATOR_ROOT <#_1_run_in_place_from_verilator_root>`__ scheme, install
|
||||
the files:
|
||||
|
||||
::
|
||||
.. code-block:: shell
|
||||
|
||||
make install
|
||||
|
||||
|
||||
@@ -18,7 +18,9 @@ Simulation Summary Report
|
||||
=========================
|
||||
|
||||
When simulation finishes, it will print a report to stdout summarizing the
|
||||
simulation. This requires the model being Verilated with :vlopt:`--main`.
|
||||
simulation. This requires the model being Verilated with :vlopt:`--main`,
|
||||
or the user's `main()` calling `VerilatedContext->statsPrintSummary()`.
|
||||
|
||||
The report may be disabled with :vlopt:`+verilator+quiet`.
|
||||
|
||||
For example:
|
||||
|
||||
@@ -304,9 +304,9 @@ GNU Make
|
||||
========
|
||||
|
||||
Verilator defaults to creating GNU Make makefiles for the model. Verilator
|
||||
will call make automatically when the :vlopt:'--build' option is used.
|
||||
will call make automatically when the :vlopt:`--build` option is used.
|
||||
|
||||
If calling Verilator from a makefile, the :vlopt:'-MMD' option will create
|
||||
If calling Verilator from a makefile, the :vlopt:`--MMD` option will create
|
||||
a dependency file, allowing Make to only run Verilator if input Verilog
|
||||
files change.
|
||||
|
||||
|
||||
+58
-23
@@ -419,9 +419,9 @@ List Of Warnings
|
||||
|
||||
.. option:: CONSTRAINTIGN
|
||||
|
||||
Warns that Verilator does not support :code:`constraint`,
|
||||
:code:`constraint_mode`, or :code:`rand_mode`, and the construct was are
|
||||
ignored.
|
||||
Warns that Verilator does not support certain forms of
|
||||
:code:`constraint`, :code:`constraint_mode`, or :code:`rand_mode`, and
|
||||
the construct was are ignored.
|
||||
|
||||
Ignoring this warning may make Verilator randomize() simulations differ
|
||||
from other simulators.
|
||||
@@ -1264,7 +1264,7 @@ List Of Warnings
|
||||
|
||||
.. option:: PINMISSING
|
||||
|
||||
.. TODO better example
|
||||
.. TODO better example (frequent)
|
||||
|
||||
Warns that a module has a pin that is not mentioned in an instance. If
|
||||
a pin is not missing it should still be specified on the instance
|
||||
@@ -1273,6 +1273,22 @@ List Of Warnings
|
||||
Ignoring this warning will only suppress the lint check; it will
|
||||
simulate correctly.
|
||||
|
||||
Faulty example:
|
||||
|
||||
.. include:: ../../docs/gen/ex_PKGNODECL_faulty.rst
|
||||
|
||||
Results in:
|
||||
|
||||
.. include:: ../../docs/gen/ex_PKGNODECL_msg.rst
|
||||
|
||||
Repaired example:
|
||||
|
||||
.. code-block:: sv
|
||||
:emphasize-lines: 2
|
||||
|
||||
sub sub (
|
||||
.port());
|
||||
|
||||
Other tools with similar warnings: Icarus Verilog's portbind, "warning:
|
||||
Instantiating module ... with dangling input port (...)". Slang's
|
||||
unconnected-port, "port '...' has no connection".
|
||||
@@ -1304,7 +1320,7 @@ List Of Warnings
|
||||
generate
|
||||
if (A==0) begin
|
||||
b b_inst1 (.x(1'b0)); //<--- error nonexistent port
|
||||
b #(.PX(1'b0)) b_inst2 (); //<--- error nonexistent parameter
|
||||
b #(.PX(1'b0)) b_inst2 (); //<--- error nonexistent parameter
|
||||
end
|
||||
endgenerate
|
||||
endmodule
|
||||
@@ -1346,11 +1362,22 @@ List Of Warnings
|
||||
|
||||
.. option:: PKGNODECL
|
||||
|
||||
.. TODO better example
|
||||
An error that a package/class appears to have been referenced that has
|
||||
not yet been declared. According to IEEE 1800-2023 26.3, all packages
|
||||
must be declared before being used.
|
||||
|
||||
An error that a package/class appears to have been referenced that has not
|
||||
yet been declared. According to IEEE 1800-2023 26.3, all packages must
|
||||
be declared before being used.
|
||||
Faulty example:
|
||||
|
||||
.. include:: ../../docs/gen/ex_PKGNODECL_faulty.rst
|
||||
|
||||
Results in:
|
||||
|
||||
.. include:: ../../docs/gen/ex_PKGNODECL_msg.rst
|
||||
|
||||
Often the package is declared in its own header file. In this case add
|
||||
an include of that package header file to the referencing file. (And
|
||||
make sure you have header guards in the package's header file to prevent
|
||||
multiple declarations of the package.)
|
||||
|
||||
|
||||
.. option:: PREPROCZERO
|
||||
@@ -1375,7 +1402,7 @@ List Of Warnings
|
||||
`endif
|
||||
|
||||
The portable way to suppress this warning is to use a define value other
|
||||
than zero to when used in a preprocessor expression.
|
||||
than zero, when it is to be used in a preprocessor expression.
|
||||
|
||||
|
||||
.. option:: PROCASSWIRE
|
||||
@@ -1897,7 +1924,8 @@ List Of Warnings
|
||||
|
||||
.. option:: UNPACKED
|
||||
|
||||
Warns that unpacked structs and unions are not supported.
|
||||
Warns that unpacked structs and unions are not supported because
|
||||
:vlopt:`--structs-packed` was used, or by up through version 5.004.
|
||||
|
||||
Ignoring this warning will make Verilator treat the structure as packed,
|
||||
which may make Verilator simulations differ from other simulators. This
|
||||
@@ -1948,14 +1976,16 @@ List Of Warnings
|
||||
|
||||
.. TODO better example
|
||||
|
||||
Warns that the specified genvar is never used/consumed.
|
||||
Warns that the specified genvar is never used/consumed. See similar
|
||||
:option:`UNUSEDSIGNAL`.
|
||||
|
||||
|
||||
.. option:: UNUSEDPARAM
|
||||
|
||||
.. TODO better example
|
||||
|
||||
Warns that the specified parameter is never used/consumed.
|
||||
Warns that the specified parameter is never used/consumed. See similar
|
||||
:option:`UNUSEDSIGNAL`.
|
||||
|
||||
|
||||
.. option:: UNUSEDSIGNAL
|
||||
@@ -2078,10 +2108,6 @@ List Of Warnings
|
||||
|
||||
.. option:: WAITCONST
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
wait(1); // Blocks forever
|
||||
|
||||
Warns that a `wait` statement awaits a constant condition, which means it
|
||||
either blocks forever or never blocks.
|
||||
|
||||
@@ -2089,6 +2115,12 @@ List Of Warnings
|
||||
something that elaborates to zero), does not warn, as it is presumed the
|
||||
code is making the intent clear.
|
||||
|
||||
Faulty example:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
wait(1); // Blocks forever
|
||||
|
||||
|
||||
.. option:: WIDTH
|
||||
|
||||
@@ -2125,7 +2157,7 @@ List Of Warnings
|
||||
|
||||
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_faulty.rst
|
||||
|
||||
Results in a WIDTHEXPAND warning:
|
||||
Results in a :option:`WIDTHEXPAND` warning:
|
||||
|
||||
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_msg.rst
|
||||
|
||||
@@ -2136,15 +2168,18 @@ List Of Warnings
|
||||
|
||||
.. option:: WIDTHTRUNC
|
||||
|
||||
A more granular WIDTH warning, for when a value is truncated.
|
||||
A more granular :option:`WIDTH` warning, for when a value is
|
||||
truncated. See :option:`WIDTH`.
|
||||
|
||||
.. option:: WIDTHEXPAND
|
||||
|
||||
A more granular WIDTH warning, for when a value is zero expanded.
|
||||
A more granular :option:`WIDTH` warning, for when a value is zero
|
||||
expanded. See :option:`WIDTH`.
|
||||
|
||||
.. option:: WIDTHXZEXPAND
|
||||
|
||||
A more granular WIDTH warning, for when a value is X/Z expanded.
|
||||
A more granular :option:`WIDTH` warning, for when a value is X/Z
|
||||
expanded. See :option:`WIDTH`.
|
||||
|
||||
.. option:: WIDTHCONCAT
|
||||
|
||||
@@ -2193,7 +2228,7 @@ List Of Warnings
|
||||
#(parameter int MY_PARAM = 0);
|
||||
reg [7:0] data;
|
||||
always @* begin
|
||||
data = {MY_PARAM{1'b1}}; //<--- WARNING
|
||||
data = {MY_PARAM{1'b1}}; //<--- Warning
|
||||
end
|
||||
endmodule
|
||||
|
||||
@@ -2214,7 +2249,7 @@ List Of Warnings
|
||||
:emphasize-lines: 2
|
||||
|
||||
module dut
|
||||
#(parameter int MY_PARAM = 1); //<--- REPAIRED
|
||||
#(parameter int MY_PARAM = 1); //<--- REPAIRED
|
||||
reg [7:0] data;
|
||||
always @* begin
|
||||
data = {MY_PARAM{1'b1}};
|
||||
|
||||
+37
-54
@@ -1472,9 +1472,6 @@ For all tests to pass, you must install the following packages:
|
||||
|
||||
- SystemC to compile the SystemC outputs, see http://systemc.org
|
||||
|
||||
- Parallel::Forker from CPAN to run tests in parallel; you can install
|
||||
this with e.g. "sudo cpan install Parallel::Forker".
|
||||
|
||||
- vcddiff to find differences in VCD outputs. See the readme at
|
||||
https://github.com/veripool/vcddiff
|
||||
|
||||
@@ -1484,7 +1481,7 @@ For all tests to pass, you must install the following packages:
|
||||
Controlling the Test Driver
|
||||
---------------------------
|
||||
|
||||
The test driver script `driver.pl` runs tests; see the `Test Driver`
|
||||
The test driver script `driver.py` runs tests; see the `Test Driver`
|
||||
section. The individual test drivers are written in Perl; see `Test
|
||||
Language`.
|
||||
|
||||
@@ -1497,7 +1494,7 @@ A specific regression test can be executed manually. To start the
|
||||
|
||||
::
|
||||
|
||||
test_regress/t/t_EXAMPLE.pl
|
||||
test_regress/t/t_EXAMPLE.py
|
||||
|
||||
|
||||
Regression Testing for Developers
|
||||
@@ -1517,13 +1514,6 @@ Developers will also want to call ./configure with two extra flags:
|
||||
disabled by default, as SystemC installation problems would otherwise
|
||||
falsely indicate a Verilator problem.
|
||||
|
||||
When enabling the long tests, some additional Perl modules are needed,
|
||||
which you can install using cpan.
|
||||
|
||||
::
|
||||
|
||||
cpan install Parallel::Forker
|
||||
|
||||
There are some traps to avoid when running regression tests
|
||||
|
||||
- When checking the MANIFEST, the test will fail on unexpected code in the
|
||||
@@ -1871,7 +1861,7 @@ represent the pointers (``op1p``, ``op2p``, etc) between the nodes.
|
||||
Debugging with GDB
|
||||
------------------
|
||||
|
||||
The `driver.pl` script accepts ``--debug --gdb`` to start
|
||||
The `driver.py` script accepts ``--debug --gdb`` to start
|
||||
Verilator under gdb and break when an error is hit, or the program is about
|
||||
to exit. You can also use ``--debug --gdbbt`` to just backtrace and then
|
||||
exit gdb. To debug the Verilated executable, use ``--gdbsim``.
|
||||
@@ -1882,7 +1872,7 @@ can use ``--debug`` and look at the underlying invocation of
|
||||
|
||||
::
|
||||
|
||||
t/t_alw_dly.pl --debug
|
||||
t/t_alw_dly.py --debug
|
||||
|
||||
shows it invokes the command:
|
||||
|
||||
@@ -1979,7 +1969,7 @@ Generally, what would you do to add a new feature?
|
||||
Follow the convention described above about the AstNode type hierarchy.
|
||||
Ordering of definitions is enforced by ``astgen``.
|
||||
|
||||
5. Now you can run ``test_regress/t/t_<newtestcase>.pl --debug`` and it'll
|
||||
5. Now you can run ``test_regress/t/t_<newtestcase>.py --debug`` and it'll
|
||||
probably fail, but you'll see a
|
||||
``test_regress/obj_dir/t_<newtestcase>/*.tree`` file which you can examine
|
||||
to see if the parsing worked. See also the sections above on debugging.
|
||||
@@ -2028,7 +2018,7 @@ IEEE 1800-2023 33 Config
|
||||
Test Driver
|
||||
===========
|
||||
|
||||
This section documents the test driver script, `driver.pl`. driver.pl
|
||||
This section documents the test driver script, `driver.py`. driver.py
|
||||
invokes Verilator or another simulator on each test file. For test file
|
||||
contents description see `Test Language`.
|
||||
|
||||
@@ -2040,7 +2030,7 @@ the regression tests with OBJCACHE enabled and in parallel on a machine
|
||||
with many cores. See the -j option and OBJCACHE environment variable.
|
||||
|
||||
|
||||
driver.pl Non-Scenario Arguments
|
||||
driver.py Non-Scenario Arguments
|
||||
--------------------------------
|
||||
|
||||
--benchmark [<cycles>]
|
||||
@@ -2110,13 +2100,13 @@ driver.pl Non-Scenario Arguments
|
||||
memory leaks.
|
||||
|
||||
--site
|
||||
Run site specific tests also.
|
||||
Run site-specific tests also.
|
||||
|
||||
--stop
|
||||
Stop on the first error.
|
||||
|
||||
--trace
|
||||
Set the simulator specific flags to request waveform tracing.
|
||||
Set the simulator-specific flags to request waveform tracing.
|
||||
|
||||
--valgrind
|
||||
Same as ``verilator --valgrind``: Run Verilator under `Valgrind <https://valgrind.org/>`_.
|
||||
@@ -2129,7 +2119,7 @@ driver.pl Non-Scenario Arguments
|
||||
For tests using the standard C++ wrapper, enable runtime debug mode.
|
||||
|
||||
|
||||
driver.pl Scenario Arguments
|
||||
driver.py Scenario Arguments
|
||||
----------------------------
|
||||
|
||||
The following options control which simulator is used, and which tests are
|
||||
@@ -2171,7 +2161,7 @@ simultaneously.
|
||||
Run Xilinx XSim simulator tests.
|
||||
|
||||
|
||||
driver.pl Environment
|
||||
driver.py Environment
|
||||
---------------------
|
||||
|
||||
HARNESS_UPDATE_GOLDEN
|
||||
@@ -2231,30 +2221,30 @@ VERILATOR_XVLOG
|
||||
Test Language
|
||||
=============
|
||||
|
||||
This section describes the format of the ``test_regress/t/*.pl`` test
|
||||
language files, executed by `driver.pl`.
|
||||
This section describes the format of the ``test_regress/t/*.py`` test
|
||||
language files, executed by `driver.py`.
|
||||
|
||||
Test Language Summary
|
||||
---------------------
|
||||
|
||||
For convenience, a summary of the most commonly used features is provided
|
||||
here, with a reference in a later section. All test files typically have a
|
||||
call to the ``lint`` or ``compile`` subroutine to compile the test. For
|
||||
run-time tests, this is followed by a call to the ``execute``
|
||||
subroutine. Both of these functions can optionally be provided with
|
||||
arguments specifying additional options.
|
||||
call to the ``test.lint`` or ``test.compile`` methods to compile the
|
||||
test. For run-time tests, this is followed by a call to the
|
||||
``test.execute`` method. Both of these functions can optionally be provided
|
||||
with arguments specifying additional options.
|
||||
|
||||
If those complete, the script calls ``ok`` to increment the count of
|
||||
successful tests and then returns 1 as its result.
|
||||
If those complete, the script calls ``test.passes`` to increment the count
|
||||
of successful tests.
|
||||
|
||||
The driver.pl script assumes by default that the source Verilog file name
|
||||
The driver.py script assumes by default that the source Verilog file name
|
||||
matches the test script name. So a test whose driver is
|
||||
``t/t_mytest.pl`` will expect a Verilog source file ``t/t_mytest.v``.
|
||||
``t/t_mytest.py`` will expect a Verilog source file ``t/t_mytest.v``.
|
||||
This can be changed using the ``top_filename`` subroutine, for example
|
||||
|
||||
::
|
||||
|
||||
top_filename("t/t_myothertest.v");
|
||||
test.top_filename = "t/t_myothertest.v"
|
||||
|
||||
By default, all tests will run with major simulators (Icarus Verilog, NC,
|
||||
VCS, ModelSim, etc.) as well as Verilator, to allow results to be
|
||||
@@ -2263,26 +2253,25 @@ can use the following:
|
||||
|
||||
::
|
||||
|
||||
scenarios(vlt => 1);
|
||||
test.scenarios('vlt')
|
||||
|
||||
Of the many options that can be set through arguments to ``compiler`` and
|
||||
``execute``, the following are particularly useful:
|
||||
Of the many options that can be set through arguments to ``test.compiler``
|
||||
and ``test.execute``, the following are particularly useful:
|
||||
|
||||
``verilator_flags2``
|
||||
A list of flags to be passed to verilator when compiling.
|
||||
|
||||
``fails``
|
||||
Set to 1 to indicate that the compilation or execution is intended to fail.
|
||||
Set true to indicate that the compilation or execution is intended to fail.
|
||||
|
||||
For example, the following would specify that compilation requires two
|
||||
defines and is expected to fail.
|
||||
|
||||
::
|
||||
|
||||
compile(
|
||||
test.compile(
|
||||
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
|
||||
fails => 1,
|
||||
);
|
||||
fails = True)
|
||||
|
||||
Hints On Writing Tests
|
||||
----------------------
|
||||
@@ -2295,10 +2284,10 @@ same name as the test, but with .cpp as suffix
|
||||
|
||||
::
|
||||
|
||||
compile(
|
||||
make_top_shell => 0,
|
||||
make_main => 0,
|
||||
verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], );
|
||||
test.compile(
|
||||
make_top_shell=False,
|
||||
make_main=False,
|
||||
verilator_flags2=["--exe", test.t_dir + "/" + test.name + ".cpp"])
|
||||
|
||||
Tests should be self-checking, rather than producing lots of output. If a
|
||||
test succeeds it should print ``*-* All Finished *-*`` to standard output
|
||||
@@ -2338,9 +2327,8 @@ compile time, it is the only option. For example:
|
||||
::
|
||||
|
||||
compile(
|
||||
fails => 1,
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
fails=True,
|
||||
expect_filename=test.golden_filename)
|
||||
|
||||
Note ``expect_filename`` strips some debugging information from the logfile
|
||||
when comparing.
|
||||
@@ -2349,9 +2337,9 @@ when comparing.
|
||||
Test Language Compile/Lint/Run Arguments
|
||||
----------------------------------------
|
||||
|
||||
This section describes common arguments to ``compile()``, ``lint()``, and
|
||||
``run()``. The full list of arguments can be found by looking at the
|
||||
``driver.pl`` source code.
|
||||
This section describes common arguments to ``test.compile``, ``test.lint``,
|
||||
and ``test.run``. The full list of arguments can be found by looking at
|
||||
the ``driver.py`` source code.
|
||||
|
||||
all_run_flags
|
||||
A list of flags to be passed when running the simulator (Verilated model
|
||||
@@ -2362,11 +2350,6 @@ check_finished
|
||||
string ``*-* All Finished *-*`` being printed on standard output. This is
|
||||
the normal way for successful tests to finish.
|
||||
|
||||
expect
|
||||
A quoted list of strings or regular expression to be matched in the
|
||||
output. See `Hints On Writing Tests` for more detail on how this argument
|
||||
should be used.
|
||||
|
||||
fails
|
||||
True to indicate this step is expected to fail. Tests that are expected
|
||||
to fail generally have _bad in their filename.
|
||||
|
||||
@@ -20,6 +20,7 @@ Ashutosh
|
||||
Ast
|
||||
Atmel
|
||||
Aurelien
|
||||
Badáň
|
||||
Bagri
|
||||
Balboni
|
||||
Baltazar
|
||||
@@ -74,6 +75,7 @@ Deepa
|
||||
Defparams
|
||||
Delm
|
||||
Denio
|
||||
Deniz
|
||||
Deprecations
|
||||
Deroo
|
||||
Desai
|
||||
@@ -109,8 +111,10 @@ Eugen
|
||||
Fabrizio
|
||||
Faucher
|
||||
Faure
|
||||
Feinberg
|
||||
Fekete
|
||||
Ferrandi
|
||||
Filip
|
||||
Flachs
|
||||
Flavien
|
||||
Florian
|
||||
@@ -149,6 +153,7 @@ Grulfen
|
||||
Gu
|
||||
Gunter
|
||||
Guo
|
||||
Güzel
|
||||
Hameed
|
||||
Hao
|
||||
Haojin
|
||||
@@ -243,6 +248,7 @@ Liwei
|
||||
Lockhart
|
||||
Longo
|
||||
Luca
|
||||
Luiza
|
||||
Lussier
|
||||
Lübeck
|
||||
MMD
|
||||
@@ -273,6 +279,8 @@ MinW
|
||||
Mindspeed
|
||||
MingW
|
||||
Miodrag
|
||||
Moberg
|
||||
Mobert
|
||||
ModelSim
|
||||
Modport
|
||||
Moinak
|
||||
@@ -354,6 +362,7 @@ Sasselli
|
||||
Scharrer
|
||||
Seitz
|
||||
Shahid
|
||||
Shahrestani
|
||||
Shankar
|
||||
Shanshan
|
||||
Sharad
|
||||
@@ -364,6 +373,7 @@ Shi
|
||||
Shinkarovsky
|
||||
Shinya
|
||||
Shirakawa
|
||||
Shou
|
||||
Shuba
|
||||
Shunyao
|
||||
Slager
|
||||
@@ -375,10 +385,12 @@ Solaris
|
||||
Solomatnikov
|
||||
Solt
|
||||
Southwell
|
||||
Spack
|
||||
Srini
|
||||
Srinivasan
|
||||
Stamness
|
||||
Stephane
|
||||
Sterin
|
||||
Stoddard
|
||||
Stroebel
|
||||
Strouble
|
||||
@@ -461,6 +473,7 @@ Wojciech
|
||||
Wolfel
|
||||
Wouters
|
||||
Wpedantic
|
||||
Wunused
|
||||
Wwarn
|
||||
XSim
|
||||
Xcelium
|
||||
@@ -497,6 +510,7 @@ architected
|
||||
args
|
||||
arrarys
|
||||
assertOn
|
||||
assertcontrol
|
||||
astgen
|
||||
async
|
||||
atClone
|
||||
@@ -513,6 +527,7 @@ basename
|
||||
bbox
|
||||
benchmarking
|
||||
biguint
|
||||
bindir
|
||||
biops
|
||||
bisonpre
|
||||
bitOpTree
|
||||
@@ -582,6 +597,7 @@ datadir
|
||||
datafiles
|
||||
david
|
||||
ddd
|
||||
de
|
||||
deassign
|
||||
debugi
|
||||
defenv
|
||||
@@ -589,6 +605,7 @@ defname
|
||||
defparam
|
||||
demangling
|
||||
dep
|
||||
deparametrized
|
||||
der
|
||||
dereference
|
||||
desassign
|
||||
@@ -701,6 +718,7 @@ genvar
|
||||
genvars
|
||||
getenv
|
||||
getline
|
||||
getter
|
||||
ggdb
|
||||
glibc
|
||||
gmake
|
||||
@@ -714,6 +732,7 @@ hh
|
||||
hier
|
||||
hierCMakeArgs
|
||||
hierMkArgs
|
||||
hierParameters
|
||||
hierVer
|
||||
hx
|
||||
hyperthreading
|
||||
@@ -845,6 +864,7 @@ parallelized
|
||||
param
|
||||
parameterization
|
||||
parameterized
|
||||
parameterized
|
||||
parameterless
|
||||
params
|
||||
parens
|
||||
@@ -858,6 +878,7 @@ phelter
|
||||
picoChip
|
||||
pinIndex
|
||||
pinout
|
||||
pkgdatadir
|
||||
plusargs
|
||||
pmos
|
||||
poping
|
||||
@@ -891,6 +912,7 @@ prototyptes
|
||||
ps
|
||||
psprintf
|
||||
pthread
|
||||
pthreads
|
||||
ptr
|
||||
pulldown
|
||||
pulldowns
|
||||
@@ -921,6 +943,7 @@ redeclaring
|
||||
regs
|
||||
reloop
|
||||
replaceShiftOp
|
||||
reproducibility
|
||||
resetall
|
||||
respecified
|
||||
rodata
|
||||
@@ -973,7 +996,9 @@ submakes
|
||||
submodule
|
||||
submodules
|
||||
substring
|
||||
superclass
|
||||
suspendable
|
||||
suspendables
|
||||
sv
|
||||
svBitVal
|
||||
svBitVecVal
|
||||
@@ -1008,6 +1033,8 @@ traceEverOn
|
||||
tran
|
||||
treei
|
||||
tri
|
||||
triand
|
||||
trior
|
||||
tristate
|
||||
tristates
|
||||
trunc
|
||||
@@ -1083,6 +1110,7 @@ warmup
|
||||
waveforms
|
||||
whitespace
|
||||
widthed
|
||||
wor
|
||||
wreal
|
||||
writeb
|
||||
writeme
|
||||
|
||||
@@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_hello_c)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create a new executable target that will contain all your sources
|
||||
@@ -35,4 +38,5 @@ target_compile_features(example PUBLIC cxx_std_14)
|
||||
# Add the Verilated circuit to the target
|
||||
verilate(example
|
||||
INCLUDE_DIRS "../make_hello_c"
|
||||
SOURCES ../make_hello_c/top.v)
|
||||
SOURCES ../make_hello_c/top.v
|
||||
)
|
||||
|
||||
@@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_hello_sc CXX)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# SystemC dependencies
|
||||
@@ -39,14 +42,12 @@ find_package(SystemCLanguage QUIET)
|
||||
add_executable(example ../make_hello_sc/sc_main.cpp)
|
||||
target_compile_features(example PUBLIC cxx_std_14)
|
||||
|
||||
set_property(
|
||||
TARGET example
|
||||
PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD}
|
||||
)
|
||||
set_property(TARGET example PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
|
||||
|
||||
# Add the Verilated circuit to the target
|
||||
verilate(example SYSTEMC
|
||||
INCLUDE_DIRS "../make_hello_sc"
|
||||
SOURCES ../make_hello_sc/top.v)
|
||||
SOURCES ../make_hello_sc/top.v
|
||||
)
|
||||
|
||||
verilator_link_systemc(example)
|
||||
|
||||
@@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_protect_lib)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create the main executable target
|
||||
@@ -55,9 +58,11 @@ verilate(verilated_secret
|
||||
VERILATOR_ARGS --protect-lib verilated_secret
|
||||
--protect-key ${PROTECT_KEY}
|
||||
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/verilated_secret
|
||||
SOURCES ../make_protect_lib/secret_impl.v)
|
||||
SOURCES ../make_protect_lib/secret_impl.v
|
||||
)
|
||||
|
||||
# Include location of verilated_secret.sv wrapper
|
||||
verilate(example
|
||||
VERILATOR_ARGS "-I${CMAKE_CURRENT_BINARY_DIR}/verilated_secret"
|
||||
SOURCES ../make_protect_lib/top.v)
|
||||
SOURCES ../make_protect_lib/top.v
|
||||
)
|
||||
|
||||
@@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_tracing_c)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# Create a new executable target that will contain all your sources
|
||||
@@ -36,4 +39,5 @@ target_compile_features(example PUBLIC cxx_std_14)
|
||||
verilate(example COVERAGE TRACE
|
||||
INCLUDE_DIRS "../make_tracing_c"
|
||||
VERILATOR_ARGS -f ../make_tracing_c/input.vc -x-assign fast
|
||||
SOURCES ../make_tracing_c/top.v)
|
||||
SOURCES ../make_tracing_c/top.v
|
||||
)
|
||||
|
||||
@@ -25,8 +25,11 @@ cmake_policy(SET CMP0074 NEW)
|
||||
project(cmake_tracing_sc_example CXX)
|
||||
|
||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||
if (NOT verilator_FOUND)
|
||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
||||
if(NOT verilator_FOUND)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||
)
|
||||
endif()
|
||||
|
||||
# SystemC dependencies
|
||||
@@ -40,15 +43,13 @@ find_package(SystemCLanguage QUIET)
|
||||
add_executable(example ../make_tracing_sc/sc_main.cpp)
|
||||
target_compile_features(example PUBLIC cxx_std_14)
|
||||
|
||||
set_property(
|
||||
TARGET example
|
||||
PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD}
|
||||
)
|
||||
set_property(TARGET example PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
|
||||
|
||||
# Add the Verilated circuit to the target
|
||||
verilate(example SYSTEMC COVERAGE TRACE
|
||||
INCLUDE_DIRS "../make_tracing_sc"
|
||||
VERILATOR_ARGS -f ../make_tracing_sc/input.vc -x-assign fast
|
||||
SOURCES ../make_tracing_sc/top.v)
|
||||
SOURCES ../make_tracing_sc/top.v
|
||||
)
|
||||
|
||||
verilator_link_systemc(example)
|
||||
|
||||
@@ -13,6 +13,6 @@ module sub
|
||||
);
|
||||
|
||||
// Some simple logic
|
||||
always_comb out = ~ in;
|
||||
always_comb out = ~in;
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -25,8 +25,7 @@ class VlFileCopy:
|
||||
|
||||
self.debug = debug
|
||||
|
||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile(
|
||||
) as meta_temp:
|
||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile() as meta_temp:
|
||||
vargs = [
|
||||
'--json-only-output',
|
||||
tree_temp.name,
|
||||
@@ -61,8 +60,7 @@ class VlFileCopy:
|
||||
print("\t%s " % command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status != 0:
|
||||
raise RuntimeError("Command failed running Verilator with '" +
|
||||
command + "', stopped")
|
||||
raise RuntimeError("Command failed running Verilator with '" + command + "', stopped")
|
||||
|
||||
|
||||
#######################################################################
|
||||
@@ -71,8 +69,7 @@ if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
description=
|
||||
"""Example of using Verilator JSON output to copy a list of files to an
|
||||
description="""Example of using Verilator JSON output to copy a list of files to an
|
||||
output directory (-odir, defaults to 'copied'), e.g. to easily create a
|
||||
tarball of the design to pass to others.
|
||||
|
||||
@@ -95,11 +92,7 @@ This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
any use, without warranty, 2019 by Wilson Snyder.
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
""")
|
||||
parser.add_argument('-debug',
|
||||
'--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('-debug', '--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('-odir',
|
||||
'--odir',
|
||||
action='store',
|
||||
@@ -108,9 +101,7 @@ SPDX-License-Identifier: CC0-1.0
|
||||
help='target output directory')
|
||||
(args, rem) = parser.parse_known_args()
|
||||
|
||||
print(
|
||||
"NOTE: vl_file_copy is only an example starting point for writing your own tool."
|
||||
)
|
||||
print("NOTE: vl_file_copy is only an example starting point for writing your own tool.")
|
||||
# That is:
|
||||
# 1. We will accept basic patches
|
||||
# 2. We are not expecting to make this globally useful. (e.g. we don't cleanup obj_dir)
|
||||
|
||||
@@ -24,8 +24,7 @@ class VlHierGraph:
|
||||
self.next_vertex_number = 0
|
||||
self.addr_to_number = {}
|
||||
|
||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile(
|
||||
) as meta_temp:
|
||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile() as meta_temp:
|
||||
vargs = [
|
||||
'--json-only-output',
|
||||
tree_temp.name,
|
||||
@@ -45,9 +44,7 @@ class VlHierGraph:
|
||||
fh.write("digraph {\n")
|
||||
fh.write(" dpi=300;\n")
|
||||
fh.write(" order=LR;\n")
|
||||
fh.write(
|
||||
" node [fontsize=8 shape=\"box\" margin=0.01 width=0 height=0]"
|
||||
)
|
||||
fh.write(" node [fontsize=8 shape=\"box\" margin=0.01 width=0 height=0]")
|
||||
fh.write(" edge [fontsize=6]")
|
||||
# Find cells
|
||||
modules = self.flatten(self.tree, lambda n: n['type'] == "MODULE")
|
||||
@@ -101,8 +98,7 @@ class VlHierGraph:
|
||||
print("\t%s " % command)
|
||||
status = subprocess.call(command, shell=True)
|
||||
if status != 0:
|
||||
raise RuntimeError("Command failed running Verilator with '" +
|
||||
command + "', stopped")
|
||||
raise RuntimeError("Command failed running Verilator with '" + command + "', stopped")
|
||||
|
||||
|
||||
#######################################################################
|
||||
@@ -111,8 +107,7 @@ if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawTextHelpFormatter,
|
||||
description=
|
||||
"""Example of using Verilator JSON output to create a .dot file showing the
|
||||
description="""Example of using Verilator JSON output to create a .dot file showing the
|
||||
design module hierarchy.
|
||||
|
||||
Example usage:
|
||||
@@ -134,11 +129,7 @@ This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
any use, without warranty, 2019 by Wilson Snyder.
|
||||
SPDX-License-Identifier: CC0-1.0
|
||||
""")
|
||||
parser.add_argument('-debug',
|
||||
'--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('-debug', '--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('-o',
|
||||
'--o',
|
||||
action='store',
|
||||
@@ -147,18 +138,14 @@ SPDX-License-Identifier: CC0-1.0
|
||||
help='output filename')
|
||||
(args, rem) = parser.parse_known_args()
|
||||
|
||||
print(
|
||||
"NOTE: vl_hier_graph is only an example starting point for writing your own tool."
|
||||
)
|
||||
print("NOTE: vl_hier_graph is only an example starting point for writing your own tool.")
|
||||
# That is:
|
||||
# 1. We will accept basic patches
|
||||
# 2. We are not expecting to make this globally useful. (e.g. we don't cleanup obj_dir)
|
||||
# 3. "make install" will not install this.
|
||||
# 4. This has not had production-worthy validation.
|
||||
|
||||
fc = VlHierGraph(output_filename=args.o,
|
||||
debug=args.debug,
|
||||
verilator_args=rem)
|
||||
fc = VlHierGraph(output_filename=args.o, debug=args.debug, verilator_args=rem)
|
||||
|
||||
######################################################################
|
||||
# Local Variables:
|
||||
|
||||
@@ -13,7 +13,7 @@ module sub
|
||||
|
||||
// Example counter/flop
|
||||
reg [31:0] count_c;
|
||||
always_ff @ (posedge clk) begin
|
||||
always_ff @(posedge clk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
@@ -32,11 +32,11 @@ module sub
|
||||
end
|
||||
|
||||
// An example assertion
|
||||
always_ff @ (posedge clk) begin
|
||||
AssertionExample: assert (!reset_l || count_c<100);
|
||||
always_ff @(posedge clk) begin
|
||||
AssertionExample : assert (!reset_l || count_c < 100);
|
||||
end
|
||||
|
||||
// And example coverage analysis
|
||||
cover property (@(posedge clk) count_c==3);
|
||||
cover property (@(posedge clk) count_c == 3);
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -14,7 +14,7 @@ module sub
|
||||
|
||||
// Example counter/flop
|
||||
reg [31:0] count_f;
|
||||
always_ff @ (posedge fastclk) begin
|
||||
always_ff @(posedge fastclk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
@@ -28,7 +28,7 @@ module sub
|
||||
|
||||
// Another example flop
|
||||
reg [31:0] count_c;
|
||||
always_ff @ (posedge clk) begin
|
||||
always_ff @(posedge clk) begin
|
||||
if (!reset_l) begin
|
||||
/*AUTORESET*/
|
||||
// Beginning of autoreset for uninitialized flops
|
||||
@@ -38,8 +38,7 @@ module sub
|
||||
else begin
|
||||
count_c <= count_c + 1;
|
||||
if (count_c >= 3) begin
|
||||
$display("[%0t] fastclk is %0d times faster than clk\n",
|
||||
$time, count_f/count_c);
|
||||
$display("[%0t] fastclk is %0d times faster than clk\n", $time, count_f / count_c);
|
||||
// This write is a magic value the Makefile uses to make sure the
|
||||
// test completes successfully.
|
||||
$write("*-* All Finished *-*\n");
|
||||
@@ -49,11 +48,11 @@ module sub
|
||||
end
|
||||
|
||||
// An example assertion
|
||||
always_ff @ (posedge clk) begin
|
||||
AssertionExample: assert(!reset_l || count_c<100);
|
||||
always_ff @(posedge clk) begin
|
||||
AssertionExample : assert (!reset_l || count_c < 100);
|
||||
end
|
||||
|
||||
// And example coverage analysis
|
||||
cover property (@(posedge clk) count_c==3);
|
||||
cover property (@(posedge clk) count_c == 3);
|
||||
|
||||
endmodule
|
||||
|
||||
@@ -130,6 +130,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
|
||||
#define FST_HDR_TIMEZERO_SIZE (8)
|
||||
#define FST_GZIO_LEN (32768)
|
||||
#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
|
||||
#define FST_ZWRAPPER_HDR_SIZE (1+8+8)
|
||||
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
#define FST_MACOSX
|
||||
@@ -549,8 +550,9 @@ return(rc);
|
||||
|
||||
static uint32_t fstReaderVarint32(FILE *f)
|
||||
{
|
||||
int chk_len = 5; /* TALOS-2023-1783 */
|
||||
unsigned char buf[chk_len];
|
||||
const int chk_len_max = 5; /* TALOS-2023-1783 */
|
||||
int chk_len = chk_len_max;
|
||||
unsigned char buf[chk_len_max];
|
||||
unsigned char *mem = buf;
|
||||
uint32_t rc = 0;
|
||||
int ch;
|
||||
@@ -581,8 +583,9 @@ return(rc);
|
||||
|
||||
static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
|
||||
{
|
||||
int chk_len = 5; /* TALOS-2023-1783 */
|
||||
unsigned char buf[chk_len];
|
||||
const int chk_len_max = 5; /* TALOS-2023-1783 */
|
||||
int chk_len = chk_len_max;
|
||||
unsigned char buf[chk_len_max];
|
||||
unsigned char *mem = buf;
|
||||
uint32_t rc = 0;
|
||||
int ch;
|
||||
@@ -614,8 +617,9 @@ return(rc);
|
||||
|
||||
static uint64_t fstReaderVarint64(FILE *f)
|
||||
{
|
||||
int chk_len = 16; /* TALOS-2023-1783 */
|
||||
unsigned char buf[chk_len];
|
||||
const int chk_len_max = 16; /* TALOS-2023-1783 */
|
||||
int chk_len = chk_len_max;
|
||||
unsigned char buf[chk_len_max];
|
||||
unsigned char *mem = buf;
|
||||
uint64_t rc = 0;
|
||||
int ch;
|
||||
@@ -4633,9 +4637,14 @@ if(sectype == FST_BL_ZWRAPPER)
|
||||
}
|
||||
#endif
|
||||
|
||||
fstReaderFseeko(xc, xc->f, 1+8+8, SEEK_SET);
|
||||
fstReaderFseeko(xc, xc->f, FST_ZWRAPPER_HDR_SIZE, SEEK_SET);
|
||||
#ifndef __MINGW32__
|
||||
fflush(xc->f);
|
||||
#else
|
||||
/* Windows UCRT runtime library reads one byte ahead in the file
|
||||
even with buffering disabled and does not synchronise the
|
||||
file position after fseek. */
|
||||
_lseek(fileno(xc->f), FST_ZWRAPPER_HDR_SIZE, SEEK_SET);
|
||||
#endif
|
||||
|
||||
zfd = dup(fileno(xc->f));
|
||||
@@ -6185,7 +6194,9 @@ struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
||||
fst_off_t blkpos = 0, prev_blkpos;
|
||||
uint64_t beg_tim, end_tim, beg_tim2, end_tim2;
|
||||
int sectype;
|
||||
#ifdef FST_DEBUG
|
||||
unsigned int secnum = 0;
|
||||
#endif
|
||||
uint64_t seclen;
|
||||
uint64_t tsec_uclen = 0, tsec_clen = 0;
|
||||
uint64_t tsec_nitems;
|
||||
@@ -6277,7 +6288,9 @@ for(;;)
|
||||
}
|
||||
|
||||
blkpos += seclen;
|
||||
#ifdef FST_DEBUG
|
||||
secnum++;
|
||||
#endif
|
||||
}
|
||||
|
||||
xc->rvat_beg_tim = beg_tim;
|
||||
|
||||
+59
-14
@@ -128,6 +128,7 @@ void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE
|
||||
|
||||
#ifndef VL_USER_STOP ///< Define this to override the vl_stop function
|
||||
void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE {
|
||||
// $stop or $fatal reporting; would break current API to add param as to which
|
||||
const char* const msg = "Verilog $stop";
|
||||
Verilated::threadContextp()->gotError(true);
|
||||
Verilated::threadContextp()->gotFinish(true);
|
||||
@@ -172,6 +173,7 @@ void vl_fatal(const char* filename, int linenum, const char* hier, const char* m
|
||||
|
||||
#ifndef VL_USER_STOP_MAYBE ///< Define this to override the vl_stop_maybe function
|
||||
void vl_stop_maybe(const char* filename, int linenum, const char* hier, bool maybe) VL_MT_UNSAFE {
|
||||
// $stop or $fatal
|
||||
Verilated::threadContextp()->errorCountInc();
|
||||
if (maybe
|
||||
&& Verilated::threadContextp()->errorCount() < Verilated::threadContextp()->errorLimit()) {
|
||||
@@ -412,6 +414,8 @@ IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
||||
data &= VL_MASK_I(obits);
|
||||
return data;
|
||||
}
|
||||
IData VL_RAND_RESET_ASSIGN_I(int obits) VL_MT_SAFE { return VL_RANDOM_I() & VL_MASK_I(obits); }
|
||||
|
||||
QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
||||
QData data = ~0ULL;
|
||||
@@ -421,11 +425,19 @@ QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
||||
data &= VL_MASK_Q(obits);
|
||||
return data;
|
||||
}
|
||||
|
||||
QData VL_RAND_RESET_ASSIGN_Q(int obits) VL_MT_SAFE { return VL_RANDOM_Q() & VL_MASK_Q(obits); }
|
||||
|
||||
WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = VL_RAND_RESET_I(32);
|
||||
outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits);
|
||||
return outwp;
|
||||
}
|
||||
WDataOutP VL_RAND_RESET_ASSIGN_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
for (int i = 0; i < VL_WORDS_I(obits) - 1; ++i) outwp[i] = VL_RAND_RESET_ASSIGN_I(32);
|
||||
outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_ASSIGN_I(32) & VL_MASK_E(obits);
|
||||
return outwp;
|
||||
}
|
||||
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||
// Not inlined to speed up compilation of slowpath code
|
||||
return VL_ZERO_W(obits, outwp);
|
||||
@@ -1753,9 +1765,8 @@ IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
|
||||
return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw);
|
||||
}
|
||||
IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE {
|
||||
char filenamez[VL_VALUE_STRING_MAX_CHARS + 1];
|
||||
_vl_vint_to_string(lhswords * VL_EDATASIZE, filenamez, lhsp);
|
||||
return VL_SYSTEM_IN(filenamez);
|
||||
const std::string lhs = VL_CVT_PACK_STR_NW(lhswords, lhsp);
|
||||
return VL_SYSTEM_IN(lhs);
|
||||
}
|
||||
IData VL_SYSTEM_IN(const std::string& lhs) VL_MT_SAFE {
|
||||
const int code = std::system(lhs.c_str()); // Yes, std::system() is threadsafe
|
||||
@@ -1905,20 +1916,16 @@ std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE {
|
||||
|
||||
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE {
|
||||
// See also _vl_vint_to_string
|
||||
char destout[VL_VALUE_STRING_MAX_CHARS + 1];
|
||||
std::string result;
|
||||
result.reserve((lwords * VL_EDATASIZE) / 8 + 1);
|
||||
const int obits = lwords * VL_EDATASIZE;
|
||||
int lsb = obits - 1;
|
||||
char* destp = destout;
|
||||
size_t len = 0;
|
||||
for (; lsb >= 0; --lsb) {
|
||||
lsb = (lsb / 8) * 8; // Next digit
|
||||
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
||||
if (charval) {
|
||||
*destp++ = static_cast<char>(charval);
|
||||
++len;
|
||||
}
|
||||
if (charval) result += static_cast<char>(charval);
|
||||
}
|
||||
return std::string{destout, len};
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string VL_CVT_PACK_STR_ND(const VlQueue<std::string>& q) VL_PURE {
|
||||
@@ -2494,9 +2501,47 @@ VerilatedContext::Serialized::Serialized() {
|
||||
m_timeprecision = picosecond; // Initial value until overridden by _Vconfigure
|
||||
}
|
||||
|
||||
bool VerilatedContext::assertOn() const VL_MT_SAFE { return m_s.m_assertOn; }
|
||||
void VerilatedContext::assertOn(bool flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
m_s.m_assertOn = flag;
|
||||
// Set all assert and directive types when true, clear otherwise.
|
||||
m_s.m_assertOn = VL_MASK_I(ASSERT_ON_WIDTH) * flag;
|
||||
}
|
||||
bool VerilatedContext::assertOnGet(VerilatedAssertType_t type,
|
||||
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE {
|
||||
// Check if selected directive type bit in the assertOn is enabled for assertion type.
|
||||
// Note: it is assumed that this is checked only for one type at the time.
|
||||
|
||||
// Flag unspecified assertion types as disabled.
|
||||
if (type == 0) return false;
|
||||
|
||||
// Get index of 3-bit group guarding assertion type status.
|
||||
// Since the assertOnGet is generated __always__ for a single assert type, we assume that only
|
||||
// a single bit will be set. Thus, ceil log2 will work fine.
|
||||
VL_DEBUG_IFDEF(assert((type & (type - 1)) == 0););
|
||||
const IData typeMaskPosition = VL_CLOG2_I(type);
|
||||
|
||||
// Check if directive type bit is enabled in corresponding assertion type bits.
|
||||
return m_s.m_assertOn & (directive << (typeMaskPosition * ASSERT_DIRECTIVE_TYPE_MASK_WIDTH));
|
||||
}
|
||||
void VerilatedContext::assertOnSet(VerilatedAssertType_t types,
|
||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||
// For each assertion type, set directive bits.
|
||||
|
||||
// Iterate through all positions of assertion type bits. If bit for this assertion type is set,
|
||||
// set directive type bits mask at this group index.
|
||||
for (int i = 0; i < std::numeric_limits<VerilatedAssertType_t>::digits; ++i) {
|
||||
if (VL_BITISSET_I(types, i))
|
||||
m_s.m_assertOn |= directives << (i * ASSERT_DIRECTIVE_TYPE_MASK_WIDTH);
|
||||
}
|
||||
}
|
||||
void VerilatedContext::assertOnClear(VerilatedAssertType_t types,
|
||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE {
|
||||
// Iterate through all positions of assertion type bits. If bit for this assertion type is set,
|
||||
// clear directive type bits mask at this group index.
|
||||
for (int i = 0; i < std::numeric_limits<VerilatedAssertType_t>::digits; ++i) {
|
||||
if (VL_BITISSET_I(types, i))
|
||||
m_s.m_assertOn &= ~(directives << (i * ASSERT_DIRECTIVE_TYPE_MASK_WIDTH));
|
||||
}
|
||||
}
|
||||
void VerilatedContext::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
@@ -2954,7 +2999,7 @@ const VerilatedScopeNameMap* VerilatedContext::scopeNameMap() VL_MT_SAFE {
|
||||
//======================================================================
|
||||
// VerilatedContext:: Methods - trace
|
||||
|
||||
void VerilatedContext::trace(VerilatedTraceBaseC* tfp, int levels, int options) VL_MT_SAFE {
|
||||
void VerilatedContext::trace(VerilatedTraceBaseC* tfp, int levels, int options) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("+ VerilatedContext::trace\n"););
|
||||
if (tfp->isOpen()) {
|
||||
VL_FATAL_MT("", 0, "",
|
||||
|
||||
+108
-74
@@ -55,6 +55,7 @@
|
||||
#include <cstring>
|
||||
#include <deque>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <set>
|
||||
@@ -153,6 +154,27 @@ enum VerilatedVarFlags {
|
||||
VLVF_DPI_CLAY = (1 << 10) // DPI compatible C standard layout
|
||||
};
|
||||
|
||||
// IEEE 1800-2023 Table 20-6
|
||||
enum class VerilatedAssertType : uint8_t {
|
||||
ASSERT_TYPE_CONCURRENT = (1 << 0),
|
||||
ASSERT_TYPE_SIMPLE_IMMEDIATE = (1 << 1),
|
||||
ASSERT_TYPE_OBSERVED_DEFERRED_IMMEDIATE = (1 << 2),
|
||||
ASSERT_TYPE_FINAL_DEFERRED_IMMEDIATE = (1 << 3),
|
||||
ASSERT_TYPE_EXPECT = (1 << 4),
|
||||
ASSERT_TYPE_UNIQUE = (1 << 5),
|
||||
ASSERT_TYPE_UNIQUE0 = (1 << 6),
|
||||
ASSERT_TYPE_PRIORITY = (1 << 7),
|
||||
};
|
||||
|
||||
// IEEE 1800-2023 Table 20-7
|
||||
enum class VerilatedAssertDirectiveType : uint8_t {
|
||||
DIRECTIVE_TYPE_ASSERT = (1 << 0),
|
||||
DIRECTIVE_TYPE_COVER = (1 << 1),
|
||||
DIRECTIVE_TYPE_ASSUME = (1 << 2),
|
||||
};
|
||||
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
|
||||
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
|
||||
|
||||
//=============================================================================
|
||||
// Utility functions
|
||||
|
||||
@@ -199,19 +221,6 @@ public:
|
||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
|
||||
/// Try to acquire mutex. Returns true on success, and false on failure.
|
||||
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return m_mutex.try_lock(); }
|
||||
/// Acquire/lock mutex and check for stop request
|
||||
/// It tries to lock the mutex and if it fails, it check if stop request was send.
|
||||
/// It returns after locking mutex.
|
||||
/// This function should be extracted to V3ThreadPool, but due to clang thread-safety
|
||||
/// limitations it needs to be placed here.
|
||||
void lockCheckStopRequest(std::function<void()> checkStopRequestFunction)
|
||||
VL_ACQUIRE() VL_MT_SAFE {
|
||||
while (true) {
|
||||
checkStopRequestFunction();
|
||||
if (m_mutex.try_lock()) return;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||
@@ -347,6 +356,19 @@ public:
|
||||
class VerilatedContext VL_NOT_FINAL {
|
||||
friend class VerilatedContextImp;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
// Numer of assertion directive type members. Then each of them will represented as 1-bit in a
|
||||
// mask.
|
||||
static constexpr size_t ASSERT_DIRECTIVE_TYPE_MASK_WIDTH = 3;
|
||||
// Specifies how many groups of directive type bit groups there are based on a number of
|
||||
// assertion types.
|
||||
// Note: we add one bit to store information whether Verilator's internal
|
||||
// directive types are enabled, for example `violation if`s.
|
||||
static constexpr size_t ASSERT_ON_WIDTH
|
||||
= ASSERT_DIRECTIVE_TYPE_MASK_WIDTH * std::numeric_limits<VerilatedAssertType_t>::digits
|
||||
+ 1;
|
||||
|
||||
protected:
|
||||
// TYPES
|
||||
using traceBaseModelCb_t
|
||||
@@ -360,7 +382,11 @@ protected:
|
||||
// No std::strings or pointers or will serialize badly!
|
||||
// Fast path
|
||||
uint64_t m_time = 0; // Current $time (unscaled), 0=at zero, or legacy
|
||||
bool m_assertOn = true; // Assertions are enabled
|
||||
std::atomic<uint32_t> m_assertOn{
|
||||
std::numeric_limits<uint32_t>::max()}; // Enabled assertions,
|
||||
// for each VerilatedAssertType we store
|
||||
// 3-bits, one for each directive type. Last
|
||||
// bit guards internal directive types.
|
||||
bool m_calcUnusedSigs = false; // Waves file on, need all signals calculated
|
||||
bool m_fatalOnError = true; // Fatal on $stop/non-fatal error
|
||||
bool m_fatalOnVpiError = true; // Fatal on vpi error/unsupported
|
||||
@@ -448,14 +474,23 @@ public:
|
||||
|
||||
// METHODS - User called
|
||||
|
||||
/// Enable assertions
|
||||
void assertOn(bool flag) VL_MT_SAFE;
|
||||
/// Return if assertions enabled
|
||||
bool assertOn() const VL_MT_SAFE { return m_s.m_assertOn; }
|
||||
/// Enable calculation of unused signals (for traces)
|
||||
void calcUnusedSigs(bool flag) VL_MT_SAFE;
|
||||
bool assertOn() const VL_MT_SAFE;
|
||||
/// Enable all assertion types
|
||||
void assertOn(bool flag) VL_MT_SAFE;
|
||||
/// Get enabled status for given assertion types
|
||||
bool assertOnGet(VerilatedAssertType_t type,
|
||||
VerilatedAssertDirectiveType_t directive) const VL_MT_SAFE;
|
||||
/// Set enabled status for given assertion types
|
||||
void assertOnSet(VerilatedAssertType_t types,
|
||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
||||
/// Clear enabled status for given assertion types
|
||||
void assertOnClear(VerilatedAssertType_t types,
|
||||
VerilatedAssertDirectiveType_t directives) VL_MT_SAFE;
|
||||
/// Return if calculating of unused signals (for traces)
|
||||
bool calcUnusedSigs() const VL_MT_SAFE { return m_s.m_calcUnusedSigs; }
|
||||
/// Enable calculation of unused signals (for traces)
|
||||
void calcUnusedSigs(bool flag) VL_MT_SAFE;
|
||||
/// Record command-line arguments, for retrieval by $test$plusargs/$value$plusargs,
|
||||
/// and for parsing +verilator+ run-time arguments.
|
||||
/// This should be called before the first model is created.
|
||||
@@ -470,52 +505,51 @@ public:
|
||||
/// Return VerilatedCovContext, allocate if needed
|
||||
/// Note if get unresolved reference then likely forgot to link verilated_cov.cpp
|
||||
VerilatedCovContext* coveragep() VL_MT_SAFE;
|
||||
/// Set debug level
|
||||
/// Return debug level
|
||||
static inline int debug() VL_MT_SAFE; /// Set debug level
|
||||
/// Debug is currently global, but for forward compatibility have a per-context method
|
||||
static inline void debug(int val) VL_MT_SAFE;
|
||||
/// Return debug level
|
||||
static inline int debug() VL_MT_SAFE;
|
||||
/// Return current number of errors/assertions
|
||||
int errorCount() const VL_MT_SAFE { return m_s.m_errorCount; }
|
||||
/// Set current number of errors/assertions
|
||||
void errorCount(int val) VL_MT_SAFE;
|
||||
/// Increment current number of errors/assertions
|
||||
void errorCountInc() VL_MT_SAFE;
|
||||
/// Return current number of errors/assertions
|
||||
int errorCount() const VL_MT_SAFE { return m_s.m_errorCount; }
|
||||
/// Set number of errors/assertions before stop
|
||||
void errorLimit(int val) VL_MT_SAFE;
|
||||
/// Return number of errors/assertions before stop
|
||||
int errorLimit() const VL_MT_SAFE { return m_s.m_errorLimit; }
|
||||
/// Set to throw fatal error on $stop/non-fatal error
|
||||
void fatalOnError(bool flag) VL_MT_SAFE;
|
||||
/// Set number of errors/assertions before stop
|
||||
void errorLimit(int val) VL_MT_SAFE;
|
||||
/// Return if to throw fatal error on $stop/non-fatal
|
||||
bool fatalOnError() const VL_MT_SAFE { return m_s.m_fatalOnError; }
|
||||
/// Set to throw fatal error on VPI errors
|
||||
void fatalOnVpiError(bool flag) VL_MT_SAFE;
|
||||
/// Set to throw fatal error on $stop/non-fatal error
|
||||
void fatalOnError(bool flag) VL_MT_SAFE;
|
||||
/// Return if to throw fatal error on VPI errors
|
||||
bool fatalOnVpiError() const VL_MT_SAFE { return m_s.m_fatalOnVpiError; }
|
||||
/// Set if got a $stop or non-fatal error
|
||||
void gotError(bool flag) VL_MT_SAFE;
|
||||
/// Set to throw fatal error on VPI errors
|
||||
void fatalOnVpiError(bool flag) VL_MT_SAFE;
|
||||
/// Return if got a $stop or non-fatal error
|
||||
bool gotError() const VL_MT_SAFE { return m_s.m_gotError; }
|
||||
/// Set if got a $finish or $stop/error
|
||||
void gotFinish(bool flag) VL_MT_SAFE;
|
||||
/// Set if got a $stop or non-fatal error
|
||||
void gotError(bool flag) VL_MT_SAFE;
|
||||
/// Return if got a $finish or $stop/error
|
||||
bool gotFinish() const VL_MT_SAFE { return m_s.m_gotFinish; }
|
||||
/// Enable quiet (also prevents need for OS calls to get CPU time)
|
||||
void quiet(bool flag) VL_MT_SAFE;
|
||||
/// Set if got a $finish or $stop/error
|
||||
void gotFinish(bool flag) VL_MT_SAFE;
|
||||
/// Return if quiet enabled
|
||||
bool quiet() const VL_MT_SAFE { return m_s.m_quiet; }
|
||||
/// Enable quiet (also prevents need for OS calls to get CPU time)
|
||||
void quiet(bool flag) VL_MT_SAFE;
|
||||
/// Return randReset value
|
||||
int randReset() VL_MT_SAFE { return m_s.m_randReset; }
|
||||
/// Select initial value of otherwise uninitialized signals.
|
||||
/// 0 = Set to zeros
|
||||
/// 1 = Set all bits to one
|
||||
/// 2 = Randomize all bits
|
||||
void randReset(int val) VL_MT_SAFE;
|
||||
/// Return randReset value
|
||||
int randReset() VL_MT_SAFE { return m_s.m_randReset; }
|
||||
/// Return default random seed
|
||||
void randSeed(int val) VL_MT_SAFE;
|
||||
/// Set default random seed, 0 = seed it automatically
|
||||
int randSeed() const VL_MT_SAFE { return m_s.m_randSeed; }
|
||||
/// Return default random seed
|
||||
void randSeed(int val) VL_MT_SAFE;
|
||||
|
||||
/// Return statistic: CPU time delta from model created until now
|
||||
double statCpuTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
@@ -607,27 +641,27 @@ public:
|
||||
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
|
||||
|
||||
// Internal: coverage
|
||||
void coverageFilename(const std::string& flag) VL_MT_SAFE;
|
||||
std::string coverageFilename() const VL_MT_SAFE;
|
||||
void coverageFilename(const std::string& flag) VL_MT_SAFE;
|
||||
|
||||
// Internal: $dumpfile
|
||||
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
std::string dumpfile() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
std::string dumpfileCheck() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
|
||||
// Internal: --prof-exec related settings
|
||||
void profExecStart(uint64_t flag) VL_MT_SAFE;
|
||||
uint64_t profExecStart() const VL_MT_SAFE { return m_ns.m_profExecStart; }
|
||||
void profExecWindow(uint64_t flag) VL_MT_SAFE;
|
||||
void profExecStart(uint64_t flag) VL_MT_SAFE;
|
||||
uint32_t profExecWindow() const VL_MT_SAFE { return m_ns.m_profExecWindow; }
|
||||
void profExecFilename(const std::string& flag) VL_MT_SAFE;
|
||||
void profExecWindow(uint64_t flag) VL_MT_SAFE;
|
||||
std::string profExecFilename() const VL_MT_SAFE;
|
||||
void profVltFilename(const std::string& flag) VL_MT_SAFE;
|
||||
void profExecFilename(const std::string& flag) VL_MT_SAFE;
|
||||
std::string profVltFilename() const VL_MT_SAFE;
|
||||
void profVltFilename(const std::string& flag) VL_MT_SAFE;
|
||||
|
||||
// Internal: SMT solver program
|
||||
void solverProgram(const std::string& flag) VL_MT_SAFE;
|
||||
std::string solverProgram() const VL_MT_SAFE;
|
||||
void solverProgram(const std::string& flag) VL_MT_SAFE;
|
||||
|
||||
// Internal: Find scope
|
||||
const VerilatedScope* scopeFind(const char* namep) const VL_MT_SAFE;
|
||||
@@ -762,8 +796,6 @@ class Verilated final {
|
||||
public:
|
||||
// METHODS - User called
|
||||
|
||||
/// Enable debug of internal verilated code
|
||||
static void debug(int level) VL_MT_SAFE;
|
||||
#ifdef VL_DEBUG
|
||||
/// Return debug level
|
||||
/// When multithreaded this may not immediately react to another thread
|
||||
@@ -773,6 +805,8 @@ public:
|
||||
/// Return constant 0 debug level, so C++'s optimizer rips up
|
||||
static constexpr int debug() VL_PURE { return 0; }
|
||||
#endif
|
||||
/// Enable debug of internal verilated code
|
||||
static void debug(int level) VL_MT_SAFE;
|
||||
|
||||
/// Set the last VerilatedContext accessed
|
||||
/// Generally threadContextp(value) should be called instead
|
||||
@@ -804,18 +838,18 @@ public:
|
||||
}
|
||||
|
||||
#ifndef VL_NO_LEGACY
|
||||
/// Call VerilatedContext::assertOn using current thread's VerilatedContext
|
||||
static void assertOn(bool flag) VL_MT_SAFE { Verilated::threadContextp()->assertOn(flag); }
|
||||
/// Return VerilatedContext::assertOn() using current thread's VerilatedContext
|
||||
static bool assertOn() VL_MT_SAFE { return Verilated::threadContextp()->assertOn(); }
|
||||
/// Call VerilatedContext::calcUnusedSigs using current thread's VerilatedContext
|
||||
static void calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->calcUnusedSigs(flag);
|
||||
}
|
||||
/// Call VerilatedContext::assertOn using current thread's VerilatedContext
|
||||
static void assertOn(bool flag) VL_MT_SAFE { Verilated::threadContextp()->assertOn(flag); }
|
||||
/// Return VerilatedContext::calcUnusedSigs using current thread's VerilatedContext
|
||||
static bool calcUnusedSigs() VL_MT_SAFE {
|
||||
return Verilated::threadContextp()->calcUnusedSigs();
|
||||
}
|
||||
/// Call VerilatedContext::calcUnusedSigs using current thread's VerilatedContext
|
||||
static void calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->calcUnusedSigs(flag);
|
||||
}
|
||||
/// Call VerilatedContext::commandArgs using current thread's VerilatedContext
|
||||
static void commandArgs(int argc, const char** argv) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->commandArgs(argc, argv);
|
||||
@@ -831,44 +865,44 @@ public:
|
||||
static const char* commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
|
||||
return Verilated::threadContextp()->commandArgsPlusMatch(prefixp);
|
||||
}
|
||||
/// Call VerilatedContext::errorLimit using current thread's VerilatedContext
|
||||
static void errorLimit(int val) VL_MT_SAFE { Verilated::threadContextp()->errorLimit(val); }
|
||||
/// Return VerilatedContext::errorLimit using current thread's VerilatedContext
|
||||
static int errorLimit() VL_MT_SAFE { return Verilated::threadContextp()->errorLimit(); }
|
||||
/// Call VerilatedContext::errorLimit using current thread's VerilatedContext
|
||||
static void errorLimit(int val) VL_MT_SAFE { Verilated::threadContextp()->errorLimit(val); }
|
||||
/// Return VerilatedContext::fatalOnError using current thread's VerilatedContext
|
||||
static bool fatalOnError() VL_MT_SAFE { return Verilated::threadContextp()->fatalOnError(); }
|
||||
/// Call VerilatedContext::fatalOnError using current thread's VerilatedContext
|
||||
static void fatalOnError(bool flag) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->fatalOnError(flag);
|
||||
}
|
||||
/// Return VerilatedContext::fatalOnError using current thread's VerilatedContext
|
||||
static bool fatalOnError() VL_MT_SAFE { return Verilated::threadContextp()->fatalOnError(); }
|
||||
/// Call VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
|
||||
static void fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->fatalOnVpiError(flag);
|
||||
}
|
||||
/// Return VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
|
||||
static bool fatalOnVpiError() VL_MT_SAFE {
|
||||
return Verilated::threadContextp()->fatalOnVpiError();
|
||||
}
|
||||
/// Call VerilatedContext::gotError using current thread's VerilatedContext
|
||||
static void gotError(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotError(flag); }
|
||||
/// Call VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
|
||||
static void fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||
Verilated::threadContextp()->fatalOnVpiError(flag);
|
||||
}
|
||||
/// Return VerilatedContext::gotError using current thread's VerilatedContext
|
||||
static bool gotError() VL_MT_SAFE { return Verilated::threadContextp()->gotError(); }
|
||||
/// Call VerilatedContext::gotFinish using current thread's VerilatedContext
|
||||
static void gotFinish(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotFinish(flag); }
|
||||
/// Call VerilatedContext::gotError using current thread's VerilatedContext
|
||||
static void gotError(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotError(flag); }
|
||||
/// Return VerilatedContext::gotFinish using current thread's VerilatedContext
|
||||
static bool gotFinish() VL_MT_SAFE { return Verilated::threadContextp()->gotFinish(); }
|
||||
/// Call VerilatedContext::randReset using current thread's VerilatedContext
|
||||
static void randReset(int val) VL_MT_SAFE { Verilated::threadContextp()->randReset(val); }
|
||||
/// Call VerilatedContext::gotFinish using current thread's VerilatedContext
|
||||
static void gotFinish(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotFinish(flag); }
|
||||
/// Return VerilatedContext::randReset using current thread's VerilatedContext
|
||||
static int randReset() VL_MT_SAFE { return Verilated::threadContextp()->randReset(); }
|
||||
/// Call VerilatedContext::randSeed using current thread's VerilatedContext
|
||||
static void randSeed(int val) VL_MT_SAFE { Verilated::threadContextp()->randSeed(val); }
|
||||
/// Call VerilatedContext::randReset using current thread's VerilatedContext
|
||||
static void randReset(int val) VL_MT_SAFE { Verilated::threadContextp()->randReset(val); }
|
||||
/// Return VerilatedContext::randSeed using current thread's VerilatedContext
|
||||
static int randSeed() VL_MT_SAFE { return Verilated::threadContextp()->randSeed(); }
|
||||
/// Call VerilatedContext::time using current thread's VerilatedContext
|
||||
static void time(uint64_t val) VL_MT_SAFE { Verilated::threadContextp()->time(val); }
|
||||
/// Call VerilatedContext::randSeed using current thread's VerilatedContext
|
||||
static void randSeed(int val) VL_MT_SAFE { Verilated::threadContextp()->randSeed(val); }
|
||||
/// Return VerilatedContext::time using current thread's VerilatedContext
|
||||
static uint64_t time() VL_MT_SAFE { return Verilated::threadContextp()->time(); }
|
||||
/// Call VerilatedContext::time using current thread's VerilatedContext
|
||||
static void time(uint64_t val) VL_MT_SAFE { Verilated::threadContextp()->time(val); }
|
||||
/// Call VerilatedContext::timeInc using current thread's VerilatedContext
|
||||
static void timeInc(uint64_t add) VL_MT_UNSAFE { Verilated::threadContextp()->timeInc(add); }
|
||||
// Deprecated
|
||||
@@ -958,8 +992,8 @@ public:
|
||||
|
||||
// Internal: Set the mtaskId, called when an mtask starts
|
||||
// Per thread, so no need to be in VerilatedContext
|
||||
static void mtaskId(uint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; }
|
||||
static uint32_t mtaskId() VL_MT_SAFE { return t_s.t_mtaskId; }
|
||||
static void mtaskId(uint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; }
|
||||
static void endOfEvalReqdInc() VL_MT_SAFE { ++t_s.t_endOfEvalReqd; }
|
||||
static void endOfEvalReqdDec() VL_MT_SAFE { --t_s.t_endOfEvalReqd; }
|
||||
|
||||
|
||||
@@ -80,6 +80,7 @@ VK_CPPFLAGS_ALWAYS += \
|
||||
-I$(VERILATOR_ROOT)/include/vltstd \
|
||||
-DVM_COVERAGE=$(VM_COVERAGE) \
|
||||
-DVM_SC=$(VM_SC) \
|
||||
-DVM_TIMING=$(VM_TIMING) \
|
||||
-DVM_TRACE=$(VM_TRACE) \
|
||||
-DVM_TRACE_FST=$(VM_TRACE_FST) \
|
||||
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \
|
||||
|
||||
@@ -93,8 +93,8 @@ public:
|
||||
/// Make all data per_instance, overriding point's per_instance
|
||||
void forcePerInstance(bool flag) VL_MT_SAFE;
|
||||
/// Write all coverage data to a file
|
||||
void write(const std::string& filename) VL_MT_SAFE;
|
||||
void write() VL_MT_SAFE { write(defaultFilename()); }
|
||||
void write(const std::string& filename) VL_MT_SAFE;
|
||||
/// Clear coverage points (and call delete on all items)
|
||||
void clear() VL_MT_SAFE;
|
||||
/// Clear items not matching the provided string
|
||||
@@ -165,8 +165,8 @@ public:
|
||||
/// Return default filename for the current thread
|
||||
static std::string defaultFilename() VL_MT_SAFE { return threadCovp()->defaultFilename(); }
|
||||
/// Write all coverage data to a file for the current thread
|
||||
static void write(const std::string& filename) VL_MT_SAFE { threadCovp()->write(filename); }
|
||||
static void write() VL_MT_SAFE { write(defaultFilename()); }
|
||||
static void write(const std::string& filename) VL_MT_SAFE { threadCovp()->write(filename); }
|
||||
/// Clear coverage points (and call delete on all items) for the current thread
|
||||
static void clear() VL_MT_SAFE { threadCovp()->clear(); }
|
||||
/// Clear items not matching the provided string for the current thread
|
||||
|
||||
@@ -127,6 +127,7 @@ void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, uint32_t elemen
|
||||
// TODO: should return std::optional<fstScopeType>, but I can't have C++17
|
||||
static std::pair<bool, fstScopeType> toFstScopeType(VerilatedTracePrefixType type) {
|
||||
switch (type) {
|
||||
case VerilatedTracePrefixType::ROOTIO_MODULE: return {true, FST_ST_VCD_MODULE};
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE: return {true, FST_ST_VCD_MODULE};
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE: return {true, FST_ST_VCD_INTERFACE};
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
@@ -137,7 +138,20 @@ static std::pair<bool, fstScopeType> toFstScopeType(VerilatedTracePrefixType typ
|
||||
}
|
||||
|
||||
void VerilatedFst::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
|
||||
const std::string newPrefix = m_prefixStack.back().first + name;
|
||||
assert(!m_prefixStack.empty()); // Constructor makes an empty entry
|
||||
std::string pname = name;
|
||||
// An empty name means this is the root of a model created with name()=="". The
|
||||
// tools get upset if we try to pass this as empty, so we put the signals under a
|
||||
// new scope, but the signals further down will be peers, not children (as usual
|
||||
// for name()!="")
|
||||
// Terminate earlier $root?
|
||||
if (m_prefixStack.back().second == VerilatedTracePrefixType::ROOTIO_MODULE) popPrefix();
|
||||
if (pname.empty()) { // Start new temporary root
|
||||
pname = "$rootio"; // VCD names are not backslash escaped
|
||||
m_prefixStack.emplace_back("", VerilatedTracePrefixType::ROOTIO_WRAPPER);
|
||||
type = VerilatedTracePrefixType::ROOTIO_MODULE;
|
||||
}
|
||||
const std::string newPrefix = m_prefixStack.back().first + pname;
|
||||
const auto pair = toFstScopeType(type);
|
||||
const bool properScope = pair.first;
|
||||
const fstScopeType scopeType = pair.second;
|
||||
@@ -149,10 +163,11 @@ void VerilatedFst::pushPrefix(const std::string& name, VerilatedTracePrefixType
|
||||
}
|
||||
|
||||
void VerilatedFst::popPrefix() {
|
||||
assert(!m_prefixStack.empty());
|
||||
const bool properScope = toFstScopeType(m_prefixStack.back().second).first;
|
||||
if (properScope) fstWriterSetUpscope(m_fst);
|
||||
m_prefixStack.pop_back();
|
||||
assert(!m_prefixStack.empty());
|
||||
assert(!m_prefixStack.empty()); // Always one left, the constructor's initial one
|
||||
}
|
||||
|
||||
void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum,
|
||||
@@ -294,7 +309,7 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
|
||||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
|
||||
void VerilatedFstBuffer::emitEvent(uint32_t code) {
|
||||
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
friend VerilatedFstBuffer; // Give the buffer access to the private bits
|
||||
|
||||
//=========================================================================
|
||||
// FST specific internals
|
||||
// FST-specific internals
|
||||
|
||||
void* m_fst = nullptr;
|
||||
std::map<uint32_t, vlFstHandle> m_code2symbol;
|
||||
@@ -177,7 +177,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
|
||||
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code);
|
||||
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||
|
||||
+347
-28
@@ -42,19 +42,20 @@ extern void vl_finish(const char* filename, int linenum, const char* hier) VL_MT
|
||||
/// Routine to call for $stop and non-fatal error
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_STOP.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
|
||||
/// Verilator internal code must call VL_STOP_MT instead, which eventually calls this.
|
||||
extern void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE;
|
||||
|
||||
/// Routine to call for fatal messages
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_FATAL.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
|
||||
/// Verilator internal code must call VL_FATAL_MT instead, which eventually calls this.
|
||||
extern void vl_fatal(const char* filename, int linenum, const char* hier,
|
||||
const char* msg) VL_MT_UNSAFE;
|
||||
|
||||
/// Routine to call for warning messages
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_WARN.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_WARN_MT instead, which eventually calls this.
|
||||
extern void vl_warn(const char* filename, int linenum, const char* hier,
|
||||
const char* msg) VL_MT_UNSAFE;
|
||||
|
||||
@@ -106,6 +107,14 @@ extern IData VL_RAND_RESET_I(int obits) VL_MT_SAFE;
|
||||
extern QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE;
|
||||
/// Random reset a signal of given width (init time only)
|
||||
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||
|
||||
/// Random reset a signal of given width (assign time only)
|
||||
extern IData VL_RAND_RESET_ASSIGN_I(int obits) VL_MT_SAFE;
|
||||
/// Random reset a signal of given width (assign time only)
|
||||
extern QData VL_RAND_RESET_ASSIGN_Q(int obits) VL_MT_SAFE;
|
||||
/// Random reset a signal of given width (assign time only)
|
||||
extern WDataOutP VL_RAND_RESET_ASSIGN_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||
|
||||
/// Zero reset a signal (slow - else use VL_ZERO_W)
|
||||
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||
|
||||
@@ -1577,49 +1586,184 @@ static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const
|
||||
return owp;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline void VL_ASSIGN_DYN_Q(VlQueue<T>& q, int elem_size, int lbits, QData from) {
|
||||
const int size = (lbits + elem_size - 1) / elem_size;
|
||||
q.renew(size);
|
||||
const QData mask = VL_MASK_Q(elem_size);
|
||||
for (int i = 0; i < size; ++i) q.at(i) = (T)((from >> (i * elem_size)) & mask);
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlQueue<CData>& q) {
|
||||
IData ret = 0;
|
||||
for (size_t i = 0; i < q.size(); ++i) ret |= static_cast<IData>(q.at(i)) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t T_Depth>
|
||||
static inline void VL_ASSIGN_UNPACK_Q(VlUnpacked<T, T_Depth>& q, size_t elem_size, QData from) {
|
||||
const QData mask = VL_MASK_Q(elem_size);
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlQueue<SData>& q) {
|
||||
IData ret = 0;
|
||||
for (size_t i = 0; i < q.size(); ++i) ret |= static_cast<IData>(q.at(i)) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlQueue<IData>& q) {
|
||||
IData ret = 0;
|
||||
for (size_t i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<CData, T_Depth>& q) {
|
||||
IData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = (T)((from >> ((T_Depth - 1 - i) * elem_size)) & mask);
|
||||
ret |= static_cast<IData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline IData VL_DYN_TO_I(const VlQueue<T>& q, int elem_size) {
|
||||
template <std::size_t T_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<SData, T_Depth>& q) {
|
||||
IData ret = 0;
|
||||
for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<IData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static inline QData VL_DYN_TO_Q(const VlQueue<T>& q, int elem_size) {
|
||||
QData ret = 0;
|
||||
for (int i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * elem_size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t T_Depth>
|
||||
static inline IData VL_UNPACK_TO_I(const VlUnpacked<T, T_Depth>& q, size_t elem_size) {
|
||||
template <std::size_t T_Depth>
|
||||
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<IData, T_Depth>& q) {
|
||||
IData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * elem_size);
|
||||
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <typename T, std::size_t T_Depth>
|
||||
static inline QData VL_UNPACK_TO_Q(const VlUnpacked<T, T_Depth>& q, size_t elem_size) {
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlQueue<CData>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * elem_size);
|
||||
for (size_t i = 0; i < q.size(); ++i) ret |= static_cast<QData>(q.at(i)) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlQueue<SData>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < q.size(); ++i) ret |= static_cast<QData>(q.at(i)) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlQueue<IData>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < q.size(); ++i) ret |= static_cast<QData>(q.at(i)) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<CData, T_Depth>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<SData, T_Depth>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline QData VL_PACK_QI(int obits, int lbits, const VlUnpacked<IData, T_Depth>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
ret |= static_cast<QData>(q[T_Depth - 1 - i]) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline QData VL_PACK_QQ(int obits, int lbits, const VlQueue<QData>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < q.size(); ++i) ret |= q.at(i) << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline QData VL_PACK_QQ(int obits, int lbits, const VlUnpacked<QData, T_Depth>& q) {
|
||||
QData ret = 0;
|
||||
for (size_t i = 0; i < T_Depth; ++i) ret |= q[T_Depth - 1 - i] << (i * lbits);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, const VlQueue<CData>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < q.size(); ++i)
|
||||
_vl_insert_WI(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, const VlQueue<SData>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < q.size(); ++i)
|
||||
_vl_insert_WI(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp, const VlQueue<IData>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < q.size(); ++i)
|
||||
_vl_insert_WI(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp,
|
||||
const VlUnpacked<CData, T_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp,
|
||||
const VlUnpacked<SData, T_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline WDataOutP VL_PACK_WI(int obits, int lbits, WDataOutP owp,
|
||||
const VlUnpacked<IData, T_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WI(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
static inline WDataOutP VL_PACK_WQ(int obits, int lbits, WDataOutP owp, const VlQueue<QData>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < q.size(); ++i)
|
||||
_vl_insert_WQ(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline WDataOutP VL_PACK_WQ(int obits, int lbits, WDataOutP owp,
|
||||
const VlUnpacked<QData, T_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WQ(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
static inline WDataOutP VL_PACK_WW(int obits, int lbits, WDataOutP owp,
|
||||
const VlQueue<VlWide<N>>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < q.size(); ++i)
|
||||
_vl_insert_WW(owp, q.at(i), i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth, std::size_t N>
|
||||
static inline WDataOutP VL_PACK_WW(int obits, int lbits, WDataOutP owp,
|
||||
const VlUnpacked<VlWide<N>, T_Depth>& q) {
|
||||
VL_MEMSET_ZERO_W(owp + 1, VL_WORDS_I(obits) - 1);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
_vl_insert_WW(owp, q[T_Depth - 1 - i], i * lbits + lbits - 1, i * lbits);
|
||||
return owp;
|
||||
}
|
||||
|
||||
// Because concats are common and wide, it's valuable to always have a clean output.
|
||||
// Thus we specify inputs must be clean, so we don't need to clean the output.
|
||||
// Note the bit shifts are always constants, so the adds in these constify out.
|
||||
@@ -2059,6 +2203,181 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataIn
|
||||
//======================================================================
|
||||
// Expressions needing insert/select
|
||||
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlQueue<CData>& q, IData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlQueue<SData>& q, IData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlQueue<IData>& q, IData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlQueue<CData>& q, QData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlQueue<SData>& q, QData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlQueue<IData>& q, QData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_QQ(int lbits, int rbits, VlQueue<QData>& q, QData from) {
|
||||
const size_t size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const QData mask = VL_MASK_Q(lbits);
|
||||
for (size_t i = 0; i < size; ++i) q.atWrite(i) = (from >> (i * lbits)) & mask;
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlQueue<CData>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
q.atWrite(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlQueue<SData>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
q.atWrite(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlQueue<IData>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
q.atWrite(i) = VL_SEL_IWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void VL_UNPACK_QW(int lbits, int rbits, VlQueue<QData>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
const QData mask = VL_MASK_Q(lbits);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
q.atWrite(i) = VL_SEL_QWII(rbits, rwp, i * lbits, lbits) & mask;
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t N>
|
||||
static inline void VL_UNPACK_WW(int lbits, int rbits, VlQueue<VlWide<N>>& q, WDataInP rwp) {
|
||||
const int size = (rbits + lbits - 1) / lbits;
|
||||
q.renew(size);
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
VL_SEL_WWII(lbits, rbits, q.atWrite(i), rwp, i * lbits, lbits);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q, IData from) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q, IData from) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_II(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q, IData from) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q, QData from) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q, QData from) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_IQ(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q, QData from) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_QQ(int lbits, int rbits, VlUnpacked<QData, T_Depth>& q, QData from) {
|
||||
const QData mask = VL_MASK_Q(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i) q[i] = (from >> ((T_Depth - 1 - i) * lbits)) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<CData, T_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<SData, T_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_IW(int lbits, int rbits, VlUnpacked<IData, T_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
const IData mask = VL_MASK_I(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = VL_SEL_IWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth>
|
||||
static inline void VL_UNPACK_QW(int lbits, int rbits, VlUnpacked<QData, T_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
const QData mask = VL_MASK_Q(lbits);
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
q[i] = VL_SEL_QWII(rbits, rwp, (T_Depth - 1 - i) * lbits, lbits) & mask;
|
||||
}
|
||||
|
||||
template <std::size_t T_Depth, std::size_t N>
|
||||
static inline void VL_UNPACK_WW(int lbits, int rbits, VlUnpacked<VlWide<N>, T_Depth>& q,
|
||||
WDataInP rwp) {
|
||||
for (size_t i = 0; i < T_Depth; ++i)
|
||||
VL_SEL_WWII(lbits, rbits, q[i], rwp, (T_Depth - 1 - i) * lbits, lbits);
|
||||
}
|
||||
|
||||
// Return QData from double (numeric)
|
||||
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
|
||||
static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {
|
||||
|
||||
@@ -12,13 +12,13 @@
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator common target specific intrinsics header
|
||||
/// \brief Verilator common target-specific intrinsics header
|
||||
///
|
||||
/// This file is not part of the Verilated public-facing API.
|
||||
///
|
||||
/// It is only for internal use; code using machine specific intrinsics for
|
||||
/// It is only for internal use; 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
|
||||
/// the target-specific headers. We provide macros to check for availability
|
||||
/// of instruction sets, and a common mechanism to disable them.
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
+141
-59
@@ -230,7 +230,7 @@ static Process& getSolver() {
|
||||
|
||||
const char* const* const cmd = &s_argv[0];
|
||||
s_solver.open(cmd);
|
||||
s_solver << "(set-logic QF_BV)\n";
|
||||
s_solver << "(set-logic QF_ABV)\n";
|
||||
s_solver << "(check-sat)\n";
|
||||
s_solver << "(reset)\n";
|
||||
std::string s;
|
||||
@@ -250,32 +250,78 @@ static Process& getSolver() {
|
||||
return s_solver;
|
||||
}
|
||||
|
||||
std::string readUntilBalanced(std::istream& stream) {
|
||||
std::string result;
|
||||
std::string token;
|
||||
int parenCount = 1;
|
||||
while (stream >> token) {
|
||||
for (const char c : token) {
|
||||
if (c == '(') {
|
||||
++parenCount;
|
||||
} else if (c == ')') {
|
||||
--parenCount;
|
||||
}
|
||||
}
|
||||
result += token + " ";
|
||||
if (parenCount == 0) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string parseNestedSelect(const std::string& nested_select_expr,
|
||||
std::vector<std::string>& indices) {
|
||||
std::istringstream nestedStream(nested_select_expr);
|
||||
std::string name, idx;
|
||||
nestedStream >> name;
|
||||
if (name == "(select") {
|
||||
const std::string further_nested_expr = readUntilBalanced(nestedStream);
|
||||
name = parseNestedSelect(further_nested_expr, indices);
|
||||
}
|
||||
std::getline(nestedStream, idx, ')');
|
||||
indices.push_back(idx);
|
||||
return name;
|
||||
}
|
||||
|
||||
std::string flattenIndices(const std::vector<std::string>& indices, const VlRandomVar* const var) {
|
||||
int flattenedIndex = 0;
|
||||
int multiplier = 1;
|
||||
for (int i = indices.size() - 1; i >= 0; --i) {
|
||||
int indexValue = 0;
|
||||
std::string trimmedIndex = indices[i];
|
||||
|
||||
trimmedIndex.erase(0, trimmedIndex.find_first_not_of(" \t"));
|
||||
trimmedIndex.erase(trimmedIndex.find_last_not_of(" \t") + 1);
|
||||
|
||||
if (trimmedIndex.find("#x") == 0) {
|
||||
indexValue = std::strtoul(trimmedIndex.substr(2).c_str(), nullptr, 16);
|
||||
} else if (trimmedIndex.find("#b") == 0) {
|
||||
indexValue = std::strtoul(trimmedIndex.substr(2).c_str(), nullptr, 2);
|
||||
} else {
|
||||
indexValue = std::strtoul(trimmedIndex.c_str(), nullptr, 10);
|
||||
}
|
||||
const int length = var->getLength(i);
|
||||
if (length == -1) {
|
||||
VL_WARN_MT(__FILE__, __LINE__, "randomize",
|
||||
"Internal: Wrong Call: Only RandomArray can call getLength()");
|
||||
break;
|
||||
}
|
||||
flattenedIndex += indexValue * multiplier;
|
||||
multiplier *= length;
|
||||
}
|
||||
std::string hexString = std::to_string(flattenedIndex);
|
||||
while (hexString.size() < 8) { hexString.insert(0, "0"); }
|
||||
return "#x" + hexString;
|
||||
}
|
||||
//======================================================================
|
||||
// VlRandomizer:: Methods
|
||||
|
||||
void VlRandomVar::emit(std::ostream& s) const { s << m_name; }
|
||||
void VlRandomConst::emit(std::ostream& s) const {
|
||||
s << "#b";
|
||||
for (int i = 0; i < m_width; i++) s << (VL_BITISSET_Q(m_val, m_width - i - 1) ? '1' : '0');
|
||||
void VlRandomVar::emitGetValue(std::ostream& s) const { s << ' ' << m_name; }
|
||||
void VlRandomVar::emitExtract(std::ostream& s, int i) const {
|
||||
s << " ((_ extract " << i << ' ' << i << ") " << m_name << ')';
|
||||
}
|
||||
void VlRandomBinOp::emit(std::ostream& s) const {
|
||||
s << '(' << m_op << ' ';
|
||||
m_lhs->emit(s);
|
||||
s << ' ';
|
||||
m_rhs->emit(s);
|
||||
s << ')';
|
||||
}
|
||||
void VlRandomExtract::emit(std::ostream& s) const {
|
||||
s << "((_ extract " << m_idx << ' ' << m_idx << ") ";
|
||||
m_expr->emit(s);
|
||||
s << ')';
|
||||
}
|
||||
bool VlRandomVar::set(std::string&& val) const {
|
||||
VlWide<VL_WQ_WORDS_E> qowp;
|
||||
VL_SET_WQ(qowp, 0ULL);
|
||||
WDataOutP owp = qowp;
|
||||
int obits = width();
|
||||
if (obits > VL_QUADSIZE) owp = reinterpret_cast<WDataOutP>(datap());
|
||||
void VlRandomVar::emitType(std::ostream& s) const { s << "(_ BitVec " << width() << ')'; }
|
||||
int VlRandomVar::totalWidth() const { return m_width; }
|
||||
static bool parseSMTNum(int obits, WDataOutP owp, const std::string& val) {
|
||||
int i;
|
||||
for (i = 0; val[i] && val[i] != '#'; i++) {}
|
||||
if (val[i++] != '#') return false;
|
||||
@@ -289,17 +335,31 @@ bool VlRandomVar::set(std::string&& val) const {
|
||||
"Internal: Unable to parse solver's randomized number");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool VlRandomVar::set(const std::string& idx, const std::string& val) const {
|
||||
VlWide<VL_WQ_WORDS_E> qowp;
|
||||
VL_SET_WQ(qowp, 0ULL);
|
||||
WDataOutP owp = qowp;
|
||||
const int obits = width();
|
||||
VlWide<VL_WQ_WORDS_E> qiwp;
|
||||
VL_SET_WQ(qiwp, 0ULL);
|
||||
if (!idx.empty() && !parseSMTNum(64, qiwp, idx)) return false;
|
||||
const int nidx = qiwp[0];
|
||||
if (obits > VL_QUADSIZE) owp = reinterpret_cast<WDataOutP>(datap(nidx));
|
||||
if (!parseSMTNum(obits, owp, val)) return false;
|
||||
|
||||
if (obits <= VL_BYTESIZE) {
|
||||
CData* const p = static_cast<CData*>(datap());
|
||||
CData* const p = static_cast<CData*>(datap(nidx));
|
||||
*p = VL_CLEAN_II(obits, obits, owp[0]);
|
||||
} else if (obits <= VL_SHORTSIZE) {
|
||||
SData* const p = static_cast<SData*>(datap());
|
||||
SData* const p = static_cast<SData*>(datap(nidx));
|
||||
*p = VL_CLEAN_II(obits, obits, owp[0]);
|
||||
} else if (obits <= VL_IDATASIZE) {
|
||||
IData* const p = static_cast<IData*>(datap());
|
||||
IData* const p = static_cast<IData*>(datap(nidx));
|
||||
*p = VL_CLEAN_II(obits, obits, owp[0]);
|
||||
} else if (obits <= VL_QUADSIZE) {
|
||||
QData* const p = static_cast<QData*>(datap());
|
||||
QData* const p = static_cast<QData*>(datap(nidx));
|
||||
*p = VL_CLEAN_QQ(obits, obits, VL_SET_QW(owp));
|
||||
} else {
|
||||
_vl_clean_inplace_w(obits, owp);
|
||||
@@ -307,27 +367,31 @@ bool VlRandomVar::set(std::string&& val) const {
|
||||
return true;
|
||||
}
|
||||
|
||||
std::shared_ptr<const VlRandomExpr> VlRandomizer::randomConstraint(VlRNG& rngr, int bits) {
|
||||
unsigned long long hash = VL_RANDOM_RNG_I(rngr) & ((1 << bits) - 1);
|
||||
std::shared_ptr<const VlRandomExpr> concat = nullptr;
|
||||
std::vector<std::shared_ptr<const VlRandomExpr>> varbits;
|
||||
for (const auto& var : m_vars) {
|
||||
for (int i = 0; i < var.second->width(); i++)
|
||||
varbits.emplace_back(std::make_shared<const VlRandomExtract>(var.second, i));
|
||||
}
|
||||
void VlRandomizer::randomConstraint(std::ostream& os, VlRNG& rngr, int bits) {
|
||||
const IData hash = VL_RANDOM_RNG_I(rngr) & ((1 << bits) - 1);
|
||||
int varBits = 0;
|
||||
for (const auto& var : m_vars) varBits += var.second->totalWidth();
|
||||
os << "(= #b";
|
||||
for (int i = bits - 1; i >= 0; i--) os << (VL_BITISSET_I(hash, i) ? '1' : '0');
|
||||
if (bits > 1) os << " (concat";
|
||||
for (int i = 0; i < bits; i++) {
|
||||
std::shared_ptr<const VlRandomExpr> bit = nullptr;
|
||||
for (unsigned j = 0; j * 2 < varbits.size(); j++) {
|
||||
unsigned idx = j + VL_RANDOM_RNG_I(rngr) % (varbits.size() - j);
|
||||
auto sel = varbits[idx];
|
||||
std::swap(varbits[idx], varbits[j]);
|
||||
bit = bit == nullptr ? sel : std::make_shared<const VlRandomBinOp>("bvxor", bit, sel);
|
||||
IData varBitsLeft = varBits;
|
||||
IData varBitsWant = (varBits + 1) / 2;
|
||||
if (varBits > 2) os << " (bvxor";
|
||||
for (const auto& var : m_vars) {
|
||||
for (int j = 0; j < var.second->totalWidth(); j++, varBitsLeft--) {
|
||||
const bool doEmit = (VL_RANDOM_RNG_I(rngr) % varBitsLeft) < varBitsWant;
|
||||
if (doEmit) {
|
||||
var.second->emitExtract(os, j);
|
||||
if (--varBitsWant == 0) break;
|
||||
}
|
||||
}
|
||||
if (varBitsWant == 0) break;
|
||||
}
|
||||
concat = concat == nullptr ? bit
|
||||
: std::make_shared<const VlRandomBinOp>("concat", concat, bit);
|
||||
if (varBits > 2) os << ')';
|
||||
}
|
||||
return std::make_shared<const VlRandomBinOp>(
|
||||
"=", concat, std::make_shared<const VlRandomConst>(hash, bits));
|
||||
if (bits > 1) os << ')';
|
||||
os << ')';
|
||||
}
|
||||
|
||||
bool VlRandomizer::next(VlRNG& rngr) {
|
||||
@@ -336,12 +400,17 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
||||
if (!f) return false;
|
||||
|
||||
f << "(set-option :produce-models true)\n";
|
||||
f << "(set-logic QF_BV)\n";
|
||||
f << "(set-logic QF_ABV)\n";
|
||||
f << "(define-fun __Vbv ((b Bool)) (_ BitVec 1) (ite b #b1 #b0))\n";
|
||||
f << "(define-fun __Vbool ((v (_ BitVec 1))) Bool (= #b1 v))\n";
|
||||
for (const auto& var : m_vars) {
|
||||
f << "(declare-fun " << var.second->name() << " () (_ BitVec " << var.second->width()
|
||||
<< "))\n";
|
||||
f << "(declare-fun " << var.second->name() << " () ";
|
||||
var.second->emitType(f);
|
||||
f << ")\n";
|
||||
}
|
||||
for (const std::string& constraint : m_constraints) {
|
||||
f << "(assert (= #b1 " << constraint << "))\n";
|
||||
}
|
||||
for (const std::string& constraint : m_constraints) { f << "(assert " << constraint << ")\n"; }
|
||||
f << "(check-sat)\n";
|
||||
|
||||
bool sat = parseSolution(f);
|
||||
@@ -349,10 +418,9 @@ bool VlRandomizer::next(VlRNG& rngr) {
|
||||
f << "(reset)\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (int i = 0; i < _VL_SOLVER_HASH_LEN_TOTAL && sat; i++) {
|
||||
f << "(assert ";
|
||||
randomConstraint(rngr, _VL_SOLVER_HASH_LEN)->emit(f);
|
||||
randomConstraint(f, rngr, _VL_SOLVER_HASH_LEN);
|
||||
f << ")\n";
|
||||
f << "\n(check-sat)\n";
|
||||
sat = parseSolution(f);
|
||||
@@ -376,7 +444,7 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||
}
|
||||
|
||||
f << "(get-value (";
|
||||
for (const auto& var : m_vars) f << var.second->name() << ' ';
|
||||
for (const auto& var : m_vars) var.second->emitGetValue(f);
|
||||
f << "))\n";
|
||||
|
||||
// Quasi-parse S-expression of the form ((x #xVALUE) (y #bVALUE) (z #xVALUE))
|
||||
@@ -396,17 +464,29 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||
"Internal: Unable to parse solver's response: invalid S-expression");
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string name, value;
|
||||
std::string name, idx, value;
|
||||
std::vector<std::string> indices;
|
||||
f >> name;
|
||||
indices.clear();
|
||||
if (name == "(select") {
|
||||
const std::string selectExpr = readUntilBalanced(f);
|
||||
name = parseNestedSelect(selectExpr, indices);
|
||||
idx = indices[0];
|
||||
}
|
||||
std::getline(f, value, ')');
|
||||
|
||||
auto it = m_vars.find(name);
|
||||
const auto it = m_vars.find(name);
|
||||
if (it == m_vars.end()) continue;
|
||||
|
||||
it->second->set(std::move(value));
|
||||
const VlRandomVar& varr = *it->second;
|
||||
if (m_randmode && !varr.randModeIdxNone()) {
|
||||
if (!(m_randmode->at(varr.randModeIdx()))) continue;
|
||||
}
|
||||
if (indices.size() > 1) {
|
||||
const std::string flattenedIndex = flattenIndices(indices, &varr);
|
||||
varr.set(flattenedIndex, value);
|
||||
} else {
|
||||
varr.set(idx, value);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -414,6 +494,8 @@ void VlRandomizer::hard(std::string&& constraint) {
|
||||
m_constraints.emplace_back(std::move(constraint));
|
||||
}
|
||||
|
||||
void VlRandomizer::clear() { m_constraints.clear(); }
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
void VlRandomizer::dump() const {
|
||||
for (const auto& var : m_vars) {
|
||||
|
||||
+167
-48
@@ -27,91 +27,210 @@
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <ostream>
|
||||
|
||||
//=============================================================================
|
||||
// VlRandomExpr and subclasses represent expressions for the constraint solver.
|
||||
|
||||
class VlRandomExpr VL_NOT_FINAL {
|
||||
public:
|
||||
virtual void emit(std::ostream& s) const = 0;
|
||||
};
|
||||
class VlRandomVar final : public VlRandomExpr {
|
||||
class VlRandomVar VL_NOT_FINAL {
|
||||
const char* const m_name; // Variable name
|
||||
void* const m_datap; // Reference to variable data
|
||||
const int m_width; // Variable width in bits
|
||||
const int m_dimension; //Variable dimension, default is 0
|
||||
const std::uint32_t m_randModeIdx; // rand_mode index
|
||||
|
||||
public:
|
||||
VlRandomVar(const char* name, int width, void* datap)
|
||||
VlRandomVar(const char* name, int width, void* datap, int dimension, std::uint32_t randModeIdx)
|
||||
: m_name{name}
|
||||
, m_datap{datap}
|
||||
, m_width{width} {}
|
||||
, m_width{width}
|
||||
, m_dimension{dimension}
|
||||
, m_randModeIdx{randModeIdx} {}
|
||||
virtual ~VlRandomVar() = default;
|
||||
const char* name() const { return m_name; }
|
||||
int width() const { return m_width; }
|
||||
void* datap() const { return m_datap; }
|
||||
bool set(std::string&&) const;
|
||||
void emit(std::ostream& s) const override;
|
||||
int dimension() const { return m_dimension; }
|
||||
virtual void* datap(int idx) const { return m_datap; }
|
||||
std::uint32_t randModeIdx() const { return m_randModeIdx; }
|
||||
bool randModeIdxNone() const { return randModeIdx() == std::numeric_limits<unsigned>::max(); }
|
||||
bool set(const std::string& idx, const std::string& val) const;
|
||||
virtual void emitGetValue(std::ostream& s) const;
|
||||
virtual void emitExtract(std::ostream& s, int i) const;
|
||||
virtual void emitType(std::ostream& s) const;
|
||||
virtual int totalWidth() const;
|
||||
virtual int getLength(int dimension) const { return -1; }
|
||||
};
|
||||
|
||||
class VlRandomConst final : public VlRandomExpr {
|
||||
const QData m_val; // Constant value
|
||||
const int m_width; // Constant width in bits
|
||||
|
||||
template <typename T>
|
||||
class VlRandomQueueVar final : public VlRandomVar {
|
||||
public:
|
||||
VlRandomConst(QData val, int width)
|
||||
: m_val{val}
|
||||
, m_width{width} {
|
||||
assert(width <= sizeof(m_val) * 8);
|
||||
VlRandomQueueVar(const char* name, int width, void* datap, int dimension,
|
||||
std::uint32_t randModeIdx)
|
||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
||||
void* datap(int idx) const override {
|
||||
return &static_cast<T*>(VlRandomVar::datap(idx))->atWrite(idx);
|
||||
}
|
||||
void emitSelect(std::ostream& s, int i) const {
|
||||
s << " (select " << name() << " #x";
|
||||
for (int j = 28; j >= 0; j -= 4) s << "0123456789abcdef"[(i >> j) & 0xf];
|
||||
s << ')';
|
||||
}
|
||||
void emitGetValue(std::ostream& s) const override {
|
||||
const int length = static_cast<T*>(VlRandomVar::datap(0))->size();
|
||||
for (int i = 0; i < length; i++) emitSelect(s, i);
|
||||
}
|
||||
void emitType(std::ostream& s) const override {
|
||||
s << "(Array (_ BitVec 32) (_ BitVec " << width() << "))";
|
||||
}
|
||||
int totalWidth() const override {
|
||||
const int length = static_cast<T*>(VlRandomVar::datap(0))->size();
|
||||
return width() * length;
|
||||
}
|
||||
void emitExtract(std::ostream& s, int i) const override {
|
||||
const int j = i / width();
|
||||
i = i % width();
|
||||
s << " ((_ extract " << i << ' ' << i << ')';
|
||||
emitSelect(s, j);
|
||||
s << ')';
|
||||
}
|
||||
void emit(std::ostream& s) const override;
|
||||
};
|
||||
|
||||
class VlRandomExtract final : public VlRandomExpr {
|
||||
const std::shared_ptr<const VlRandomExpr> m_expr; // Sub-expression
|
||||
const unsigned m_idx; // Extracted index
|
||||
|
||||
template <typename T>
|
||||
class VlRandomArrayVar final : public VlRandomVar {
|
||||
public:
|
||||
VlRandomExtract(std::shared_ptr<const VlRandomExpr> expr, unsigned idx)
|
||||
: m_expr{expr}
|
||||
, m_idx{idx} {}
|
||||
void emit(std::ostream& s) const override;
|
||||
VlRandomArrayVar(const char* name, int width, void* datap, int dimension,
|
||||
std::uint32_t randModeIdx)
|
||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
||||
|
||||
void* datap(int idx) const override {
|
||||
if (idx < 0) return &static_cast<T*>(VlRandomVar::datap(0))->operator[](0);
|
||||
std::vector<size_t> indices(dimension());
|
||||
for (int dim = dimension() - 1; dim >= 0; --dim) {
|
||||
const int length = getLength(dim);
|
||||
indices[dim] = idx % length;
|
||||
idx /= length;
|
||||
}
|
||||
return &static_cast<T*>(VlRandomVar::datap(0))->find_element(indices);
|
||||
}
|
||||
|
||||
void emitSelect(std::ostream& s, const std::vector<int>& indices) const {
|
||||
for (size_t idx = 0; idx < indices.size(); ++idx) s << "(select ";
|
||||
s << name();
|
||||
for (size_t idx = 0; idx < indices.size(); ++idx) {
|
||||
s << " #x";
|
||||
for (int j = 28; j >= 0; j -= 4) {
|
||||
s << "0123456789abcdef"[(indices[idx] >> j) & 0xf];
|
||||
}
|
||||
s << ")";
|
||||
}
|
||||
}
|
||||
|
||||
int getLength(int dimension) const override {
|
||||
const auto var = static_cast<const T*>(datap(-1));
|
||||
const int lenth = var->find_length(dimension);
|
||||
return lenth;
|
||||
}
|
||||
|
||||
void emitGetValue(std::ostream& s) const override {
|
||||
const int total_dimensions = dimension();
|
||||
std::vector<int> lengths;
|
||||
for (int dim = 0; dim < total_dimensions; dim++) {
|
||||
const int len = getLength(dim);
|
||||
lengths.push_back(len);
|
||||
}
|
||||
std::vector<int> indices(total_dimensions, 0);
|
||||
while (true) {
|
||||
emitSelect(s, indices);
|
||||
int currentDimension = total_dimensions - 1;
|
||||
while (currentDimension >= 0
|
||||
&& ++indices[currentDimension] >= lengths[currentDimension]) {
|
||||
indices[currentDimension] = 0;
|
||||
--currentDimension;
|
||||
}
|
||||
if (currentDimension < 0) break;
|
||||
}
|
||||
}
|
||||
|
||||
void emitType(std::ostream& s) const override {
|
||||
if (dimension() > 0) {
|
||||
for (int i = 0; i < dimension(); ++i) s << "(Array (_ BitVec 32) ";
|
||||
s << "(_ BitVec " << width() << ")";
|
||||
for (int i = 0; i < dimension(); ++i) s << ")";
|
||||
}
|
||||
}
|
||||
|
||||
int totalWidth() const override {
|
||||
int totalLength = 1;
|
||||
for (int dim = 0; dim < dimension(); ++dim) {
|
||||
const int length = getLength(dim);
|
||||
if (length == -1) return 0;
|
||||
totalLength *= length;
|
||||
}
|
||||
return width() * totalLength;
|
||||
}
|
||||
|
||||
void emitExtract(std::ostream& s, int i) const override {
|
||||
const int j = i / width();
|
||||
i = i % width();
|
||||
std::vector<int> indices(dimension());
|
||||
int idx = j;
|
||||
for (int dim = dimension() - 1; dim >= 0; --dim) {
|
||||
int length = getLength(dim);
|
||||
indices[dim] = idx % length;
|
||||
idx /= length;
|
||||
}
|
||||
s << " ((_ extract " << i << ' ' << i << ')';
|
||||
emitSelect(s, indices);
|
||||
s << ')';
|
||||
}
|
||||
};
|
||||
|
||||
class VlRandomBinOp final : public VlRandomExpr {
|
||||
const char* const m_op; // Binary operation identifier
|
||||
const std::shared_ptr<const VlRandomExpr> m_lhs, m_rhs; // Sub-expressions
|
||||
|
||||
public:
|
||||
VlRandomBinOp(const char* op, std::shared_ptr<const VlRandomExpr> lhs,
|
||||
std::shared_ptr<const VlRandomExpr> rhs)
|
||||
: m_op{op}
|
||||
, m_lhs{lhs}
|
||||
, m_rhs{rhs} {}
|
||||
void emit(std::ostream& s) const override;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlRandomizer is the object holding constraints and variable references.
|
||||
|
||||
class VlRandomizer final {
|
||||
// MEMBERS
|
||||
std::vector<std::string> m_constraints; // Solver-dependent constraints
|
||||
std::map<std::string, std::shared_ptr<const VlRandomVar>>
|
||||
m_vars; // Solver-dependent variables
|
||||
std::map<std::string, std::shared_ptr<const VlRandomVar>> m_vars; // Solver-dependent
|
||||
// variables
|
||||
const VlQueue<CData>* m_randmode; // rand_mode state;
|
||||
|
||||
// PRIVATE METHODS
|
||||
std::shared_ptr<const VlRandomExpr> randomConstraint(VlRNG& rngr, int bits);
|
||||
void randomConstraint(std::ostream& os, VlRNG& rngr, int bits);
|
||||
bool parseSolution(std::iostream& file);
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlRandomizer() = default;
|
||||
~VlRandomizer() = default;
|
||||
|
||||
// METHODS
|
||||
// Finds the next solution satisfying the constraints
|
||||
bool next(VlRNG& rngr);
|
||||
template <typename T>
|
||||
void write_var(T& var, int width, const char* name) {
|
||||
auto it = m_vars.find(name);
|
||||
if (it != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomVar>(name, width, &var);
|
||||
void write_var(T& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
// TODO: make_unique once VlRandomizer is per-instance not per-ref
|
||||
m_vars[name]
|
||||
= std::make_shared<const VlRandomVar>(name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
template <typename T>
|
||||
void write_var(VlQueue<T>& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomQueueVar<VlQueue<T>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
template <typename T, std::size_t N>
|
||||
void write_var(VlUnpacked<T, N>& var, int width, const char* name, int dimension,
|
||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||
if (m_vars.find(name) != m_vars.end()) return;
|
||||
m_vars[name] = std::make_shared<const VlRandomArrayVar<VlUnpacked<T, N>>>(
|
||||
name, width, &var, dimension, randmodeIdx);
|
||||
}
|
||||
void hard(std::string&& constraint);
|
||||
void clear();
|
||||
void set_randmode(const VlQueue<CData>& randmode) { m_randmode = &randmode; }
|
||||
#ifdef VL_DEBUG
|
||||
void dump() const;
|
||||
#endif
|
||||
|
||||
@@ -95,8 +95,7 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, std::strlen(VLTSAVE_HEADER_STR)))) {
|
||||
const std::string fn = filename();
|
||||
const std::string msg
|
||||
= std::
|
||||
string{"Can't deserialize; file has wrong header signature, or file not found: "}
|
||||
= "Can't deserialize; file has wrong header signature, or file not found: "s
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
// Die before we close() as close would infinite loop
|
||||
|
||||
@@ -40,7 +40,7 @@ package std;
|
||||
|
||||
task put(T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
if (m_bound != 0)
|
||||
while (m_bound != 0 && m_queue.size() >= m_bound)
|
||||
wait (m_queue.size() < m_bound);
|
||||
m_queue.push_back(message);
|
||||
`endif
|
||||
@@ -56,7 +56,9 @@ package std;
|
||||
|
||||
task get(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
while (m_queue.size() == 0) begin
|
||||
wait (m_queue.size() > 0);
|
||||
end
|
||||
message = m_queue.pop_front();
|
||||
`endif
|
||||
endtask
|
||||
@@ -71,7 +73,9 @@ package std;
|
||||
|
||||
task peek(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
while (m_queue.size() == 0) begin
|
||||
wait (m_queue.size() > 0);
|
||||
end
|
||||
message = m_queue[0];
|
||||
`endif
|
||||
endtask
|
||||
@@ -98,7 +102,9 @@ package std;
|
||||
|
||||
task get(int keyCount = 1);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_keyCount >= keyCount);
|
||||
while (m_keyCount < keyCount) begin
|
||||
wait (m_keyCount >= keyCount);
|
||||
end
|
||||
m_keyCount -= keyCount;
|
||||
`endif
|
||||
endtask
|
||||
@@ -189,4 +195,7 @@ package std;
|
||||
$urandom(s.atoi()); // Set the seed using a string
|
||||
endfunction
|
||||
endclass
|
||||
function int randomize();
|
||||
randomize = 0;
|
||||
endfunction
|
||||
endpackage
|
||||
|
||||
+22
-15
@@ -49,10 +49,12 @@ class VerilatedTraceOffloadBuffer;
|
||||
//=============================================================================
|
||||
// Common enumerations
|
||||
|
||||
enum class VerilatedTracePrefixType : uint32_t {
|
||||
enum class VerilatedTracePrefixType : uint8_t {
|
||||
// Note: Entries must match VTracePrefixType (by name, not necessarily by value)
|
||||
ARRAY_PACKED,
|
||||
ARRAY_UNPACKED,
|
||||
ROOTIO_MODULE, // $rootio, used when name()=="", other modules become peers
|
||||
ROOTIO_WRAPPER, // "Above" ROOTIO_MODULE
|
||||
SCOPE_MODULE,
|
||||
SCOPE_INTERFACE,
|
||||
STRUCT_PACKED,
|
||||
@@ -61,7 +63,7 @@ enum class VerilatedTracePrefixType : uint32_t {
|
||||
};
|
||||
|
||||
// Direction attribute for ports
|
||||
enum class VerilatedTraceSigDirection : uint32_t {
|
||||
enum class VerilatedTraceSigDirection : uint8_t {
|
||||
NONE,
|
||||
INPUT,
|
||||
OUTPUT,
|
||||
@@ -69,7 +71,7 @@ enum class VerilatedTraceSigDirection : uint32_t {
|
||||
};
|
||||
|
||||
// Kind of signal. Similar to nettype but with a few more alternatives
|
||||
enum class VerilatedTraceSigKind : uint32_t {
|
||||
enum class VerilatedTraceSigKind : uint8_t {
|
||||
PARAMETER,
|
||||
SUPPLY0,
|
||||
SUPPLY1,
|
||||
@@ -81,7 +83,7 @@ enum class VerilatedTraceSigKind : uint32_t {
|
||||
};
|
||||
|
||||
// Base data type of signal
|
||||
enum class VerilatedTraceSigType : uint32_t {
|
||||
enum class VerilatedTraceSigType : uint8_t {
|
||||
DOUBLE,
|
||||
INTEGER,
|
||||
BIT,
|
||||
@@ -198,8 +200,8 @@ public:
|
||||
//=============================================================================
|
||||
// VerilatedTrace
|
||||
|
||||
// T_Trace is the format specific subclass of VerilatedTrace.
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
// T_Trace is the format-specific subclass of VerilatedTrace.
|
||||
// T_Buffer is the format-specific base class of VerilatedTraceBuffer.
|
||||
template <class T_Trace, class T_Buffer>
|
||||
class VerilatedTrace VL_NOT_FINAL {
|
||||
public:
|
||||
@@ -348,7 +350,7 @@ private:
|
||||
|
||||
protected:
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
// Internals available to format-specific implementations
|
||||
|
||||
mutable VerilatedMutex m_mutex; // Ensure dump() etc only called from single thread
|
||||
|
||||
@@ -381,7 +383,7 @@ protected:
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Virtual functions to be provided by the format specific implementation
|
||||
// Virtual functions to be provided by the format-specific implementation
|
||||
|
||||
// Called when the trace moves forward to a new time point
|
||||
virtual void emitTimeChange(uint64_t timeui) = 0;
|
||||
@@ -438,7 +440,7 @@ public:
|
||||
//=============================================================================
|
||||
// VerilatedTraceBuffer
|
||||
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
// T_Buffer is the format-specific base class of VerilatedTraceBuffer.
|
||||
// The format-specific hot-path methods use duck-typing via T_Buffer for performance.
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceBuffer VL_NOT_FINAL : public T_Buffer {
|
||||
@@ -464,7 +466,7 @@ public:
|
||||
// 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
|
||||
// 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.
|
||||
@@ -487,7 +489,8 @@ public:
|
||||
void fullQData(uint32_t* oldp, QData newval, int bits);
|
||||
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
|
||||
void fullDouble(uint32_t* oldp, double newval);
|
||||
void fullEvent(uint32_t* oldp, const VlEventBase* newval);
|
||||
void fullEvent(uint32_t* oldp, const VlEventBase* newvalp);
|
||||
void fullEventTriggered(uint32_t* oldp);
|
||||
|
||||
// In non-offload mode, these are called directly by the trace callbacks,
|
||||
// and are called chg*. In offload mode, they are called by the worker
|
||||
@@ -524,9 +527,10 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newval) {
|
||||
fullEvent(oldp, newval);
|
||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newvalp) {
|
||||
if (newvalp->isTriggered()) fullEvent(oldp, newvalp);
|
||||
}
|
||||
VL_ATTR_ALWINLINE void chgEventTriggered(uint32_t* oldp) { fullEventTriggered(oldp); }
|
||||
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
|
||||
double old;
|
||||
std::memcpy(&old, oldp, sizeof(old));
|
||||
@@ -537,7 +541,7 @@ public:
|
||||
//=============================================================================
|
||||
// VerilatedTraceOffloadBuffer
|
||||
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
// T_Buffer is the format-specific base class of VerilatedTraceBuffer.
|
||||
// The format-specific hot-path methods use duck-typing via T_Buffer for performance.
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceOffloadBuffer final : public VerilatedTraceBuffer<T_Buffer> {
|
||||
@@ -605,7 +609,10 @@ public:
|
||||
m_offloadBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgEvent(uint32_t code, const VlEventBase* newval) {
|
||||
void chgEvent(uint32_t code, const VlEventBase* newvalp) {
|
||||
if (newvalp->isTriggered()) chgEventTriggered(code);
|
||||
}
|
||||
void chgEventTriggered(uint32_t code) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
//=============================================================================
|
||||
//
|
||||
// Verilated tracing implementation code template common to all formats.
|
||||
// This file is included by the format specific implementations and
|
||||
// This file is included by the format-specific implementations and
|
||||
// should not be used otherwise.
|
||||
//
|
||||
//=============================================================================
|
||||
@@ -169,7 +169,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_EVENT:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
|
||||
traceBufp->chgEvent(oldp, reinterpret_cast<const VlEventBase*>(readp));
|
||||
traceBufp->chgEventTriggered(oldp);
|
||||
continue;
|
||||
|
||||
//===
|
||||
@@ -299,7 +299,7 @@ VerilatedTrace<VL_SUB_T, VL_BUF_T>::~VerilatedTrace() {
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
// Internals available to format-specific implementations
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||
@@ -401,7 +401,7 @@ bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const std::stri
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
// Internals available to format-specific implementations
|
||||
|
||||
template <>
|
||||
std::string VerilatedTrace<VL_SUB_T, VL_BUF_T>::timeResStr() const {
|
||||
@@ -543,7 +543,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
|
||||
|
||||
Verilated::quiesce();
|
||||
|
||||
// Call hook for format specific behaviour
|
||||
// Call hook for format-specific behaviour
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
if (!preFullDump()) return;
|
||||
} else {
|
||||
@@ -667,7 +667,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addModel(VerilatedModel* modelp)
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Cannot use parallel tracing with offloading");
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
// Configure format specific sub class
|
||||
// Configure format-specific sub class
|
||||
configure(*(configp.get()));
|
||||
}
|
||||
|
||||
@@ -818,8 +818,8 @@ VerilatedTraceBuffer<VL_BUF_T>::VerilatedTraceBuffer(Trace& owner)
|
||||
, m_sigs_enabledp{owner.m_sigs_enabledp} {}
|
||||
|
||||
// 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
|
||||
// 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 <>
|
||||
@@ -831,10 +831,17 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newval) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, const VlEventBase* newvalp) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = 1; // Do we really store an "event" ?
|
||||
emitEvent(code, newval);
|
||||
// No need to update *oldp
|
||||
if (newvalp->isTriggered()) emitEvent(code);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEventTriggered(uint32_t* oldp) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
// No need to update *oldp
|
||||
emitEvent(code);
|
||||
}
|
||||
|
||||
template <>
|
||||
|
||||
+141
-99
@@ -485,6 +485,8 @@ private:
|
||||
|
||||
public:
|
||||
using const_iterator = typename Deque::const_iterator;
|
||||
template <class Func>
|
||||
using WithFuncReturnType = decltype(std::declval<Func>()(0, std::declval<T_Value>()));
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
@@ -512,28 +514,29 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
static VlQueue cons(const T_Value& lhs) {
|
||||
// Construct new object from _V_alue and/or _C_ontainer child objects
|
||||
static VlQueue consV(const T_Value& lhs) {
|
||||
VlQueue out;
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const T_Value& lhs, const T_Value& rhs) {
|
||||
static VlQueue consVV(const T_Value& lhs, const T_Value& rhs) {
|
||||
VlQueue out;
|
||||
out.push_back(rhs);
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const VlQueue& lhs, const T_Value& rhs) {
|
||||
static VlQueue consCV(const VlQueue& lhs, const T_Value& rhs) {
|
||||
VlQueue out = lhs;
|
||||
out.push_front(rhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const T_Value& lhs, const VlQueue& rhs) {
|
||||
static VlQueue consVC(const T_Value& lhs, const VlQueue& rhs) {
|
||||
VlQueue out = rhs;
|
||||
out.push_back(lhs);
|
||||
return out;
|
||||
}
|
||||
static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) {
|
||||
static VlQueue consCC(const VlQueue& lhs, const VlQueue& rhs) {
|
||||
VlQueue out = rhs;
|
||||
for (const auto& i : lhs.m_deque) out.push_back(i);
|
||||
return out;
|
||||
@@ -592,18 +595,28 @@ public:
|
||||
return v;
|
||||
}
|
||||
|
||||
// Setting. Verilog: assoc[index] = v
|
||||
// Can't just overload operator[] or provide a "at" reference to set,
|
||||
// because we need to be able to insert only when the value is set
|
||||
T_Value& at(int32_t index) {
|
||||
// Setting. Verilog: assoc[index] = v (should only be used by dynamic arrays)
|
||||
T_Value& atWrite(int32_t index) {
|
||||
// cppcheck-suppress variableScope
|
||||
static thread_local T_Value t_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||
t_throwAway = atDefault();
|
||||
return t_throwAway;
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
return m_deque[index];
|
||||
}
|
||||
// Setting. Verilog: assoc[index] = v (should only be used by queues)
|
||||
T_Value& atWriteAppend(int32_t index) {
|
||||
// cppcheck-suppress variableScope
|
||||
static thread_local T_Value t_throwAway;
|
||||
if (VL_UNLIKELY(index < 0 || index > m_deque.size())) {
|
||||
t_throwAway = atDefault();
|
||||
return t_throwAway;
|
||||
} else if (VL_UNLIKELY(index == m_deque.size())) {
|
||||
push_back(atDefault());
|
||||
}
|
||||
return m_deque[index];
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(int32_t index) const {
|
||||
@@ -615,7 +628,7 @@ public:
|
||||
}
|
||||
}
|
||||
// Access with an index counted from end (e.g. q[$])
|
||||
T_Value& atBack(int32_t index) { return at(m_deque.size() - 1 - index); }
|
||||
T_Value& atWriteAppendBack(int32_t index) { return atWriteAppend(m_deque.size() - 1 - index); }
|
||||
const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); }
|
||||
|
||||
// function void q.insert(index, value);
|
||||
@@ -751,7 +764,7 @@ public:
|
||||
// Can't use std::find_if as need index number
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(index, i)) return VlQueue::cons(i);
|
||||
if (with_func(index, i)) return VlQueue::consV(i);
|
||||
++index;
|
||||
}
|
||||
return VlQueue{};
|
||||
@@ -760,7 +773,7 @@ public:
|
||||
VlQueue<IData> find_first_index(Func with_func) const {
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(index, i)) return VlQueue<IData>::cons(index);
|
||||
if (with_func(index, i)) return VlQueue<IData>::consV(index);
|
||||
++index;
|
||||
}
|
||||
return VlQueue<IData>{};
|
||||
@@ -769,7 +782,7 @@ public:
|
||||
VlQueue find_last(Func with_func) const {
|
||||
IData index = m_deque.size() - 1;
|
||||
for (auto& item : vlstd::reverse_view(m_deque)) {
|
||||
if (with_func(index, item)) return VlQueue::cons(item);
|
||||
if (with_func(index, item)) return VlQueue::consV(item);
|
||||
--index;
|
||||
}
|
||||
return VlQueue{};
|
||||
@@ -778,7 +791,7 @@ public:
|
||||
VlQueue<IData> find_last_index(Func with_func) const {
|
||||
IData index = m_deque.size() - 1;
|
||||
for (auto& item : vlstd::reverse_view(m_deque)) {
|
||||
if (with_func(index, item)) return VlQueue<IData>::cons(index);
|
||||
if (with_func(index, item)) return VlQueue<IData>::consV(index);
|
||||
--index;
|
||||
}
|
||||
return VlQueue<IData>{};
|
||||
@@ -788,7 +801,7 @@ public:
|
||||
VlQueue min() const {
|
||||
if (m_deque.empty()) return VlQueue{};
|
||||
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend());
|
||||
return VlQueue::cons(*it);
|
||||
return VlQueue::consV(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue min(Func with_func) const {
|
||||
@@ -797,12 +810,12 @@ public:
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
return VlQueue::cons(*it);
|
||||
return VlQueue::consV(*it);
|
||||
}
|
||||
VlQueue max() const {
|
||||
if (m_deque.empty()) return VlQueue{};
|
||||
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend());
|
||||
return VlQueue::cons(*it);
|
||||
return VlQueue::consV(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue max(Func with_func) const {
|
||||
@@ -811,7 +824,7 @@ public:
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
return VlQueue::cons(*it);
|
||||
return VlQueue::consV(*it);
|
||||
}
|
||||
|
||||
T_Value r_sum() const {
|
||||
@@ -820,70 +833,63 @@ public:
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_sum(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out += with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_product() const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.cbegin();
|
||||
T_Value out{*it};
|
||||
++it;
|
||||
for (; it != m_deque.cend(); ++it) out *= *it;
|
||||
if (m_deque.empty()) return T_Value(0); // The big three do it this way
|
||||
T_Value out = T_Value(1);
|
||||
for (const auto& i : m_deque) out *= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_product(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.cbegin();
|
||||
WithFuncReturnType<Func> r_product(Func with_func) const {
|
||||
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
|
||||
IData index = 0;
|
||||
T_Value out{with_func(index, *it)};
|
||||
++it;
|
||||
++index;
|
||||
for (; it != m_deque.cend(); ++it) out *= with_func(index++, *it);
|
||||
for (const auto& i : m_deque) out *= with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_and() const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.cbegin();
|
||||
T_Value out{*it};
|
||||
++it;
|
||||
for (; it != m_deque.cend(); ++it) out &= *it;
|
||||
if (m_deque.empty()) return T_Value(0); // The big three do it this way
|
||||
T_Value out = ~T_Value(0);
|
||||
for (const auto& i : m_deque) out &= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_and(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.cbegin();
|
||||
WithFuncReturnType<Func> r_and(Func with_func) const {
|
||||
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
IData index = 0;
|
||||
T_Value out{with_func(index, *it)};
|
||||
++it;
|
||||
++index;
|
||||
for (; it != m_deque.cend(); ++it) out &= with_func(index, *it);
|
||||
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
|
||||
for (const auto& i : m_deque) out &= with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_or() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_deque) out |= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_or(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out |= with_func(index++, i);
|
||||
return out;
|
||||
}
|
||||
T_Value r_xor() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
#ifdef VERILATOR_BIG3_NULLARY_ARITHMETICS_QUIRKS
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
#endif
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_deque) out ^= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_xor(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out ^= with_func(index++, i);
|
||||
return out;
|
||||
@@ -920,6 +926,9 @@ private:
|
||||
|
||||
public:
|
||||
using const_iterator = typename Map::const_iterator;
|
||||
template <class Func>
|
||||
using WithFuncReturnType
|
||||
= decltype(std::declval<Func>()(std::declval<T_Key>(), std::declval<T_Value>()));
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
@@ -1092,7 +1101,7 @@ public:
|
||||
return with_func(i.first, i.second);
|
||||
});
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
@@ -1101,7 +1110,7 @@ public:
|
||||
return with_func(i.first, i.second);
|
||||
});
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Key>::cons(it->first);
|
||||
return VlQueue<T_Key>::consV(it->first);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_last(Func with_func) const {
|
||||
@@ -1109,7 +1118,7 @@ public:
|
||||
m_map.crbegin(), m_map.crend(),
|
||||
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
|
||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
@@ -1117,7 +1126,7 @@ public:
|
||||
m_map.crbegin(), m_map.crend(),
|
||||
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
|
||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Key>::cons(it->first);
|
||||
return VlQueue<T_Key>::consV(it->first);
|
||||
}
|
||||
|
||||
// Reduction operators
|
||||
@@ -1128,7 +1137,7 @@ public:
|
||||
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> min(Func with_func) const {
|
||||
@@ -1138,7 +1147,7 @@ public:
|
||||
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||
return with_func(a.first, a.second) < with_func(b.first, b.second);
|
||||
});
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
VlQueue<T_Value> max() const {
|
||||
if (m_map.empty()) return VlQueue<T_Value>();
|
||||
@@ -1147,7 +1156,7 @@ public:
|
||||
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||
return a.second < b.second;
|
||||
});
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> max(Func with_func) const {
|
||||
@@ -1157,7 +1166,7 @@ public:
|
||||
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||
return with_func(a.first, a.second) < with_func(b.first, b.second);
|
||||
});
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
return VlQueue<T_Value>::consV(it->second);
|
||||
}
|
||||
|
||||
T_Value r_sum() const {
|
||||
@@ -1166,64 +1175,56 @@ public:
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_sum(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
for (const auto& i : m_map) out += with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_product() const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.cbegin();
|
||||
T_Value out{it->second};
|
||||
++it;
|
||||
for (; it != m_map.cend(); ++it) out *= it->second;
|
||||
if (m_map.empty()) return T_Value(0); // The big three do it this way
|
||||
T_Value out = T_Value(1);
|
||||
for (const auto& i : m_map) out *= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_product(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.cbegin();
|
||||
T_Value out{with_func(it->first, it->second)};
|
||||
++it;
|
||||
for (; it != m_map.cend(); ++it) out *= with_func(it->first, it->second);
|
||||
WithFuncReturnType<Func> r_product(Func with_func) const {
|
||||
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
|
||||
for (const auto& i : m_map) out *= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_and() const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.cbegin();
|
||||
T_Value out{it->second};
|
||||
++it;
|
||||
for (; it != m_map.cend(); ++it) out &= it->second;
|
||||
if (m_map.empty()) return T_Value(0); // The big three do it this way
|
||||
T_Value out = ~T_Value(0);
|
||||
for (const auto& i : m_map) out &= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_and(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.cbegin();
|
||||
T_Value out{with_func(it->first, it->second)};
|
||||
++it;
|
||||
for (; it != m_map.cend(); ++it) out &= with_func(it->first, it->second);
|
||||
WithFuncReturnType<Func> r_and(Func with_func) const {
|
||||
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
|
||||
for (const auto& i : m_map) out &= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_or() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_map) out |= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_map) out |= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
T_Value r_xor() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
T_Value out = T_Value(0);
|
||||
for (const auto& i : m_map) out ^= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
WithFuncReturnType<Func> r_xor(Func with_func) const {
|
||||
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
|
||||
return out;
|
||||
}
|
||||
@@ -1311,6 +1312,43 @@ public:
|
||||
WData* data() { return &m_storage[0]; }
|
||||
const WData* data() const { return &m_storage[0]; }
|
||||
|
||||
std::size_t size() const { return T_Depth; }
|
||||
// To fit C++14
|
||||
template <std::size_t CurrentDimension = 0, typename U = T_Value>
|
||||
int find_length(int dimension, std::false_type) const {
|
||||
return size();
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0, typename U = T_Value>
|
||||
int find_length(int dimension, std::true_type) const {
|
||||
if (dimension == CurrentDimension) {
|
||||
return size();
|
||||
} else {
|
||||
return m_storage[0].template find_length<CurrentDimension + 1>(dimension);
|
||||
}
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0>
|
||||
int find_length(int dimension) const {
|
||||
return find_length<CurrentDimension>(dimension, std::is_class<T_Value>{});
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0, typename U = T_Value>
|
||||
auto& find_element(const std::vector<size_t>& indices, std::false_type) {
|
||||
return m_storage[indices[CurrentDimension]];
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0, typename U = T_Value>
|
||||
auto& find_element(const std::vector<size_t>& indices, std::true_type) {
|
||||
return m_storage[indices[CurrentDimension]].template find_element<CurrentDimension + 1>(
|
||||
indices);
|
||||
}
|
||||
|
||||
template <std::size_t CurrentDimension = 0>
|
||||
auto& find_element(const std::vector<size_t>& indices) {
|
||||
return find_element<CurrentDimension>(indices, std::is_class<T_Value>{});
|
||||
}
|
||||
|
||||
T_Value& operator[](size_t index) { return m_storage[index]; }
|
||||
const T_Value& operator[](size_t index) const { return m_storage[index]; }
|
||||
|
||||
@@ -1438,7 +1476,7 @@ public:
|
||||
// Can't use std::find_if as need index number
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
if (with_func(index, i)) return VlQueue<T_Value>::cons(i);
|
||||
if (with_func(index, i)) return VlQueue<T_Value>::consV(i);
|
||||
++index;
|
||||
}
|
||||
return VlQueue<T_Value>{};
|
||||
@@ -1447,7 +1485,7 @@ public:
|
||||
VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
IData index = 0;
|
||||
for (const auto& i : m_storage) {
|
||||
if (with_func(index, i)) return VlQueue<IData>::cons(index);
|
||||
if (with_func(index, i)) return VlQueue<IData>::consV(index);
|
||||
++index;
|
||||
}
|
||||
return VlQueue<T_Key>{};
|
||||
@@ -1455,14 +1493,14 @@ public:
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_last(Func with_func) const {
|
||||
for (int i = T_Depth - 1; i >= 0; i--) {
|
||||
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::cons(m_storage[i]);
|
||||
if (with_func(i, m_storage[i])) return VlQueue<T_Value>::consV(m_storage[i]);
|
||||
}
|
||||
return VlQueue<T_Value>{};
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
for (int i = T_Depth - 1; i >= 0; i--) {
|
||||
if (with_func(i, m_storage[i])) return VlQueue<IData>::cons(i);
|
||||
if (with_func(i, m_storage[i])) return VlQueue<IData>::consV(i);
|
||||
}
|
||||
return VlQueue<T_Key>{};
|
||||
}
|
||||
@@ -1470,7 +1508,7 @@ public:
|
||||
// Reduction operators
|
||||
VlQueue<T_Value> min() const {
|
||||
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage));
|
||||
return VlQueue<T_Value>::cons(*it);
|
||||
return VlQueue<T_Value>::consV(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> min(Func with_func) const {
|
||||
@@ -1478,11 +1516,11 @@ public:
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
return VlQueue<T_Value>::cons(*it);
|
||||
return VlQueue<T_Value>::consV(*it);
|
||||
}
|
||||
VlQueue<T_Value> max() const {
|
||||
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage));
|
||||
return VlQueue<T_Value>::cons(*it);
|
||||
return VlQueue<T_Value>::consV(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> max(Func with_func) const {
|
||||
@@ -1490,7 +1528,7 @@ public:
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
return VlQueue<T_Value>::cons(*it);
|
||||
return VlQueue<T_Value>::consV(*it);
|
||||
}
|
||||
|
||||
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||
@@ -1786,12 +1824,16 @@ public:
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Represents the null pointer. Used for setting VlClassRef to null instead of
|
||||
// via nullptr_t, to prevent the implicit conversion of 0 to nullptr.
|
||||
// Represents the null pointer. Used for:
|
||||
// * setting VlClassRef to null instead of via nullptr_t, to prevent the implicit conversion of 0
|
||||
// to nullptr,
|
||||
// * comparing interface pointers to null.
|
||||
|
||||
struct VlNull final {
|
||||
operator bool() const { return false; }
|
||||
bool operator==(const void* ptr) const { return !ptr; }
|
||||
};
|
||||
inline bool operator==(const void* ptr, VlNull) { return !ptr; }
|
||||
|
||||
//===================================================================
|
||||
// Verilog class reference container
|
||||
|
||||
+23
-12
@@ -305,8 +305,22 @@ void VerilatedVcd::printIndent(int level_change) {
|
||||
}
|
||||
|
||||
void VerilatedVcd::pushPrefix(const std::string& name, VerilatedTracePrefixType type) {
|
||||
std::string newPrefix = m_prefixStack.back().first + name;
|
||||
assert(!m_prefixStack.empty()); // Constructor makes an empty entry
|
||||
std::string pname = name;
|
||||
// An empty name means this is the root of a model created with name()=="". The
|
||||
// tools get upset if we try to pass this as empty, so we put the signals under a
|
||||
// new scope, but the signals further down will be peers, not children (as usual
|
||||
// for name()!="")
|
||||
// Terminate earlier $root?
|
||||
if (m_prefixStack.back().second == VerilatedTracePrefixType::ROOTIO_MODULE) popPrefix();
|
||||
if (pname.empty()) { // Start new temporary root
|
||||
pname = "$rootio"; // VCD names are not backslash escaped
|
||||
m_prefixStack.emplace_back("", VerilatedTracePrefixType::ROOTIO_WRAPPER);
|
||||
type = VerilatedTracePrefixType::ROOTIO_MODULE;
|
||||
}
|
||||
std::string newPrefix = m_prefixStack.back().first + pname;
|
||||
switch (type) {
|
||||
case VerilatedTracePrefixType::ROOTIO_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
@@ -326,7 +340,9 @@ void VerilatedVcd::pushPrefix(const std::string& name, VerilatedTracePrefixType
|
||||
}
|
||||
|
||||
void VerilatedVcd::popPrefix() {
|
||||
assert(!m_prefixStack.empty());
|
||||
switch (m_prefixStack.back().second) {
|
||||
case VerilatedTracePrefixType::ROOTIO_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_MODULE:
|
||||
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||
@@ -338,7 +354,7 @@ void VerilatedVcd::popPrefix() {
|
||||
default: break;
|
||||
}
|
||||
m_prefixStack.pop_back();
|
||||
assert(!m_prefixStack.empty());
|
||||
assert(!m_prefixStack.empty()); // Always one left, the constructor's initial one
|
||||
}
|
||||
|
||||
void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, bool array,
|
||||
@@ -573,16 +589,11 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
|
||||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedVcdBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
|
||||
const bool triggered = newval->isTriggered();
|
||||
// TODO : It seems that untriggered events are not filtered
|
||||
// should be tested before this last step
|
||||
if (triggered) {
|
||||
// Don't prefetch suffix as it's a bit too late;
|
||||
char* wp = m_writep;
|
||||
*wp++ = '1';
|
||||
finishLine(code, wp);
|
||||
}
|
||||
void VerilatedVcdBuffer::emitEvent(uint32_t code) {
|
||||
// Don't prefetch suffix as it's a bit too late;
|
||||
char* wp = m_writep;
|
||||
*wp++ = '1';
|
||||
finishLine(code, wp);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
|
||||
@@ -43,7 +43,7 @@ private:
|
||||
friend VerilatedVcdBuffer; // Give the buffer access to the private bits
|
||||
|
||||
//=========================================================================
|
||||
// VCD specific internals
|
||||
// VCD-specific internals
|
||||
|
||||
VerilatedVcdFile* m_filep; // File we're writing to
|
||||
bool m_fileNewed; // m_filep needs destruction
|
||||
@@ -214,7 +214,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
|
||||
// Implementation of VerilatedTraceBuffer interface
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, const VlEventBase* newval);
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code);
|
||||
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||
|
||||
@@ -896,6 +896,9 @@ public:
|
||||
if (VL_LIKELY(it != s().m_futureCbs.cend())) return it->first.first;
|
||||
return ~0ULL; // maxquad
|
||||
}
|
||||
static bool hasCbs(const uint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
return !s().m_cbCurrentLists[reason].empty();
|
||||
}
|
||||
static bool callCbs(const uint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: callCbs reason=%u\n", reason););
|
||||
assertOneCheck();
|
||||
@@ -958,8 +961,8 @@ public:
|
||||
}
|
||||
static void dumpCbs() VL_MT_UNSAFE_ONE;
|
||||
static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info
|
||||
static void evalNeeded(bool evalNeeded) { s().m_evalNeeded = evalNeeded; }
|
||||
static bool evalNeeded() { return s().m_evalNeeded; }
|
||||
static void evalNeeded(bool evalNeeded) { s().m_evalNeeded = evalNeeded; }
|
||||
static void inertialDelay(const VerilatedVpioVar* vop, p_vpi_value valuep) {
|
||||
s().m_inertialPuts.emplace_back(vop, valuep);
|
||||
}
|
||||
@@ -1056,6 +1059,10 @@ bool VerilatedVpi::callCbs(uint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
return VerilatedVpiImp::callCbs(reason);
|
||||
}
|
||||
|
||||
bool VerilatedVpi::hasCbs(uint32_t reason) VL_MT_UNSAFE_ONE {
|
||||
return VerilatedVpiImp::hasCbs(reason);
|
||||
}
|
||||
|
||||
// Historical, before we had multiple kinds of timed callbacks
|
||||
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callCbs(cbAfterDelay); }
|
||||
|
||||
@@ -2468,7 +2475,7 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||
vl_strprintf(t_outDynamicStr, "%u",
|
||||
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
|
||||
} else if (varp->vltype() == VLVT_UINT64) {
|
||||
vl_strprintf(t_outDynamicStr, "%llu",
|
||||
vl_strprintf(t_outDynamicStr, "%llu", // lintok-format-ll
|
||||
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(varDatap))));
|
||||
}
|
||||
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||
@@ -2690,7 +2697,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
||||
} else if (valuep->format == vpiDecStrVal) {
|
||||
char remainder[16];
|
||||
unsigned long long val;
|
||||
const int success = std::sscanf(valuep->value.str, "%30llu%15s", &val, remainder);
|
||||
const int success = std::sscanf(valuep->value.str, "%30llu%15s", // lintok-format-ll
|
||||
&val, remainder);
|
||||
if (success < 1) {
|
||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
|
||||
__func__, valuep->value.str,
|
||||
|
||||
@@ -49,6 +49,9 @@ public:
|
||||
/// Call callbacks of arbitrary types.
|
||||
/// User wrapper code should call this from their main loops.
|
||||
static bool callCbs(uint32_t reason) VL_MT_UNSAFE_ONE;
|
||||
/// Returns true if there are callbacks of the given reason registered.
|
||||
/// User wrapper code should call this from their main loops.
|
||||
static bool hasCbs(uint32_t reason) VL_MT_UNSAFE_ONE;
|
||||
/// Returns time of the next registered VPI callback, or
|
||||
/// ~(0ULL) if none are registered
|
||||
static QData cbNextDeadline() VL_MT_UNSAFE_ONE;
|
||||
|
||||
+16
-5
@@ -200,6 +200,11 @@
|
||||
|
||||
// Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||
#define VL_PURE VL_CLANG_ATTR(annotate("PURE"))
|
||||
// Annotated function can be called only in MT_DISABLED context, i.e. either in a code unit
|
||||
// compiled with VL_MT_DISABLED_CODE_UNIT preprocessor definition, or in the main thread.
|
||||
#define VL_MT_DISABLED \
|
||||
VL_CLANG_ATTR(annotate("MT_DISABLED")) \
|
||||
VL_EXCLUDES(VlOs::MtScopeMutex::s_haveThreadScope)
|
||||
// Comment tag that function is threadsafe
|
||||
#define VL_MT_SAFE VL_CLANG_ATTR(annotate("MT_SAFE"))
|
||||
// Comment tag that function is threadsafe, only if
|
||||
@@ -216,7 +221,7 @@
|
||||
// protected to make sure single-caller
|
||||
#define VL_MT_UNSAFE_ONE VL_CLANG_ATTR(annotate("MT_UNSAFE_ONE"))
|
||||
// Comment tag that function is entry point of parallelization
|
||||
#define VL_MT_START VL_CLANG_ATTR(annotate("MT_START"))
|
||||
#define VL_MT_START VL_CLANG_ATTR(annotate("MT_START")) VL_REQUIRES(VlOs::MtScopeMutex::s_haveThreadScope)
|
||||
|
||||
#ifndef VL_NO_LEGACY
|
||||
# define VL_ULL(c) (c##ULL) // Add appropriate suffix to 64-bit constant (deprecated)
|
||||
@@ -463,8 +468,6 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
||||
#define VL_VALUE_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||
#endif
|
||||
|
||||
#define VL_VALUE_STRING_MAX_CHARS (VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE / VL_BYTESIZE)
|
||||
|
||||
//=========================================================================
|
||||
// Base macros
|
||||
|
||||
@@ -588,9 +591,9 @@ static inline double VL_ROUND(double n) {
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Macros controlling target specific optimizations
|
||||
// Macros controlling target-specific optimizations
|
||||
|
||||
// Define VL_PORTABLE_ONLY to disable all 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
|
||||
@@ -653,6 +656,14 @@ public:
|
||||
return (m_start == 0.0) ? 0.0 : gettime() - m_start;
|
||||
}
|
||||
};
|
||||
|
||||
// Used by clang's -fthread-safety, ensures that only one instance of V3ThreadScope
|
||||
// is created at a time
|
||||
class VL_CAPABILITY("mutex") MtScopeMutex final {
|
||||
public:
|
||||
static MtScopeMutex s_haveThreadScope;
|
||||
};
|
||||
|
||||
} //namespace VlOs
|
||||
|
||||
//=========================================================================
|
||||
|
||||
@@ -51,10 +51,10 @@ double DeltaCpuTime::gettime() VL_MT_SAFE {
|
||||
#else
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
timespec ts;
|
||||
if (0 != clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) // MT-Safe
|
||||
if (0 == clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts)) // MT-Safe // LCOV_EXCL_BR_LINE
|
||||
return ts.tv_sec + ts.tv_nsec * 1e-9;
|
||||
#endif
|
||||
return 0.0;
|
||||
return 0.0; // LCOV_EXCL_LINE
|
||||
}
|
||||
double DeltaWallTime::gettime() VL_MT_SAFE {
|
||||
#if defined(_WIN32) || defined(__MINGW32__)
|
||||
@@ -66,9 +66,9 @@ double DeltaWallTime::gettime() VL_MT_SAFE {
|
||||
#else
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||
timespec ts;
|
||||
if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) // MT-Safe
|
||||
if (0 == clock_gettime(CLOCK_MONOTONIC, &ts)) // MT-Safe // LCOV_EXCL_BR_LINE
|
||||
return ts.tv_sec + ts.tv_nsec * 1e-9;
|
||||
return 0.0;
|
||||
return 0.0; // LCOV_EXCL_LINE
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
+165
-222
@@ -48,9 +48,11 @@ def fully_qualified_name(node):
|
||||
if node.kind == CursorKind.TRANSLATION_UNIT:
|
||||
return []
|
||||
res = fully_qualified_name(node.semantic_parent)
|
||||
displayname = node.displayname
|
||||
displayname = [displayname] if displayname else []
|
||||
if res:
|
||||
return res + ([node.displayname] if node.displayname else [])
|
||||
return [node.displayname] if node.displayname else []
|
||||
return res + displayname
|
||||
return displayname
|
||||
|
||||
|
||||
# Returns True, if `class_node` contains node
|
||||
@@ -106,9 +108,8 @@ class VlAnnotations:
|
||||
|
||||
def is_mt_safe_call(self):
|
||||
return (not self.is_mt_unsafe_call()
|
||||
and (self.mt_safe or self.mt_safe_postinit or self.pure
|
||||
or self.requires or self.excludes or self.acquire
|
||||
or self.release))
|
||||
and (self.mt_safe or self.mt_safe_postinit or self.pure or self.requires
|
||||
or self.excludes or self.acquire or self.release))
|
||||
|
||||
def is_pure_call(self):
|
||||
return self.pure
|
||||
@@ -140,31 +141,32 @@ class VlAnnotations:
|
||||
result = VlAnnotations()
|
||||
for node in nodes:
|
||||
if node.kind == CursorKind.ANNOTATE_ATTR:
|
||||
if node.displayname == "MT_START":
|
||||
displayname = node.displayname
|
||||
if displayname == "MT_START":
|
||||
result.mt_start = True
|
||||
elif node.displayname == "MT_SAFE":
|
||||
elif displayname == "MT_SAFE":
|
||||
result.mt_safe = True
|
||||
elif node.displayname == "MT_STABLE":
|
||||
elif displayname == "MT_STABLE":
|
||||
result.stable_tree = True
|
||||
elif node.displayname == "MT_SAFE_POSTINIT":
|
||||
elif displayname == "MT_SAFE_POSTINIT":
|
||||
result.mt_safe_postinit = True
|
||||
elif node.displayname == "MT_UNSAFE":
|
||||
elif displayname == "MT_UNSAFE":
|
||||
result.mt_unsafe = True
|
||||
elif node.displayname == "MT_UNSAFE_ONE":
|
||||
elif displayname == "MT_UNSAFE_ONE":
|
||||
result.mt_unsafe_one = True
|
||||
elif node.displayname == "MT_DISABLED":
|
||||
elif displayname == "MT_DISABLED":
|
||||
result.mt_disabled = True
|
||||
elif node.displayname == "PURE":
|
||||
elif displayname == "PURE":
|
||||
result.pure = True
|
||||
elif node.displayname in ["ACQUIRE", "ACQUIRE_SHARED"]:
|
||||
elif displayname in ["ACQUIRE", "ACQUIRE_SHARED"]:
|
||||
result.acquire = True
|
||||
elif node.displayname in ["RELEASE", "RELEASE_SHARED"]:
|
||||
elif displayname in ["RELEASE", "RELEASE_SHARED"]:
|
||||
result.release = True
|
||||
elif node.displayname == "REQUIRES":
|
||||
elif displayname == "REQUIRES":
|
||||
result.requires = True
|
||||
elif node.displayname in ["EXCLUDES", "MT_SAFE_EXCLUDES"]:
|
||||
elif displayname in ["EXCLUDES", "MT_SAFE_EXCLUDES"]:
|
||||
result.excludes = True
|
||||
elif node.displayname == "GUARDED_BY":
|
||||
elif displayname == "GUARDED_BY":
|
||||
result.guarded = True
|
||||
# Attributes are always at the beginning
|
||||
elif not node.kind.is_attribute():
|
||||
@@ -203,9 +205,7 @@ class FunctionInfo:
|
||||
annotations: VlAnnotations
|
||||
ftype: FunctionType
|
||||
|
||||
_hash: Optional[int] = dataclasses.field(default=None,
|
||||
init=False,
|
||||
repr=False)
|
||||
_hash: Optional[int] = dataclasses.field(default=None, init=False, repr=False)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
@@ -220,15 +220,13 @@ class FunctionInfo:
|
||||
return self._hash
|
||||
|
||||
def __eq__(self, other):
|
||||
return (self.usr == other.usr and self.file == other.file
|
||||
and self.line == other.line)
|
||||
return (self.usr == other.usr and self.file == other.file and self.line == other.line)
|
||||
|
||||
def copy(self, /, **changes):
|
||||
return dataclasses.replace(self, **changes)
|
||||
|
||||
@staticmethod
|
||||
def from_decl_file_line_and_refd_node(file: str, line: int,
|
||||
refd: clang.cindex.Cursor,
|
||||
def from_decl_file_line_and_refd_node(file: str, line: int, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
file = os.path.abspath(file)
|
||||
refd = refd.canonical
|
||||
@@ -277,14 +275,11 @@ class Diagnostic:
|
||||
source_ctx: FunctionInfo
|
||||
kind: DiagnosticKind
|
||||
|
||||
_hash: Optional[int] = dataclasses.field(default=None,
|
||||
init=False,
|
||||
repr=False)
|
||||
_hash: Optional[int] = dataclasses.field(default=None, init=False, repr=False)
|
||||
|
||||
def __hash__(self):
|
||||
if not self._hash:
|
||||
self._hash = hash(
|
||||
hash(self.target) ^ hash(self.source_ctx) ^ hash(self.kind))
|
||||
self._hash = hash(hash(self.target) ^ hash(self.source_ctx) ^ hash(self.kind))
|
||||
return self._hash
|
||||
|
||||
|
||||
@@ -292,9 +287,9 @@ class CallAnnotationsValidator:
|
||||
|
||||
def __init__(self, diagnostic_cb: Callable[[Diagnostic], None],
|
||||
is_ignored_top_level: Callable[[clang.cindex.Cursor], bool],
|
||||
is_ignored_def: Callable[
|
||||
[clang.cindex.Cursor, clang.cindex.Cursor], bool],
|
||||
is_ignored_call: Callable[[clang.cindex.Cursor], bool]):
|
||||
is_ignored_def: Callable[[clang.cindex.Cursor, clang.cindex.Cursor],
|
||||
bool], is_ignored_call: Callable[[clang.cindex.Cursor],
|
||||
bool]):
|
||||
self._diagnostic_cb = diagnostic_cb
|
||||
self._is_ignored_top_level = is_ignored_top_level
|
||||
self._is_ignored_call = is_ignored_call
|
||||
@@ -312,6 +307,7 @@ class CallAnnotationsValidator:
|
||||
self._defines: dict[str, str] = {}
|
||||
self._call_location: Optional[FunctionInfo] = None
|
||||
self._caller: Optional[FunctionInfo] = None
|
||||
self._base_func_declarations: dict[str, clang.cindex.Cursor] = {}
|
||||
self._constructor_context: list[clang.cindex.Cursor] = []
|
||||
self._level: int = 0
|
||||
|
||||
@@ -329,8 +325,7 @@ class CallAnnotationsValidator:
|
||||
with open(source_file, "r", encoding="utf-8") as file:
|
||||
for line in file:
|
||||
line = line.strip()
|
||||
match = re.fullmatch(
|
||||
r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line)
|
||||
match = re.fullmatch(r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line)
|
||||
if match:
|
||||
if match.group(1).startswith("define"):
|
||||
key = match.group(2)
|
||||
@@ -341,16 +336,14 @@ class CallAnnotationsValidator:
|
||||
return defs
|
||||
|
||||
@staticmethod
|
||||
def filter_out_unsupported_compiler_args(
|
||||
args: list[str]) -> tuple[list[str], dict[str, str]]:
|
||||
def filter_out_unsupported_compiler_args(args: list[str]) -> tuple[list[str], dict[str, str]]:
|
||||
filtered_args = []
|
||||
defines = {}
|
||||
args_iter = iter(args)
|
||||
try:
|
||||
while arg := next(args_iter):
|
||||
# Skip positional arguments (input file name).
|
||||
if not arg.startswith("-") and (arg.endswith(".cpp")
|
||||
or arg.endswith(".c")
|
||||
if not arg.startswith("-") and (arg.endswith(".cpp") or arg.endswith(".c")
|
||||
or arg.endswith(".h")):
|
||||
continue
|
||||
|
||||
@@ -367,8 +360,7 @@ class CallAnnotationsValidator:
|
||||
# Preserved options with separate value argument.
|
||||
if arg in [
|
||||
"-x"
|
||||
"-Xclang", "-I", "-isystem", "-iquote", "-include",
|
||||
"-include-pch"
|
||||
"-Xclang", "-I", "-isystem", "-iquote", "-include", "-include-pch"
|
||||
]:
|
||||
filtered_args += [arg, next(args_iter)]
|
||||
continue
|
||||
@@ -406,14 +398,12 @@ class CallAnnotationsValidator:
|
||||
|
||||
return (filtered_args, defines)
|
||||
|
||||
def compile_and_analyze_file(self, source_file: str,
|
||||
compiler_args: list[str],
|
||||
def compile_and_analyze_file(self, source_file: str, compiler_args: list[str],
|
||||
build_dir: Optional[str]):
|
||||
filename = os.path.abspath(source_file)
|
||||
initial_cwd = "."
|
||||
|
||||
filtered_args, defines = self.filter_out_unsupported_compiler_args(
|
||||
compiler_args)
|
||||
filtered_args, defines = self.filter_out_unsupported_compiler_args(compiler_args)
|
||||
defines.update(self.parse_initial_defines(source_file))
|
||||
|
||||
if build_dir:
|
||||
@@ -451,8 +441,7 @@ class CallAnnotationsValidator:
|
||||
self._diagnostic_cb(Diagnostic(target, source, source_ctx, kind))
|
||||
else:
|
||||
self._diagnostic_cb(
|
||||
Diagnostic(FunctionInfo.from_node(target), source, source_ctx,
|
||||
kind))
|
||||
Diagnostic(FunctionInfo.from_node(target), source, source_ctx, kind))
|
||||
|
||||
def iterate_children(self, children: Iterable[clang.cindex.Cursor],
|
||||
handler: Callable[[clang.cindex.Cursor], None]):
|
||||
@@ -465,8 +454,7 @@ class CallAnnotationsValidator:
|
||||
@staticmethod
|
||||
def get_referenced_node_info(
|
||||
node: clang.cindex.Cursor
|
||||
) -> tuple[bool, Optional[clang.cindex.Cursor], VlAnnotations,
|
||||
Iterable[clang.cindex.Cursor]]:
|
||||
) -> tuple[bool, Optional[clang.cindex.Cursor], VlAnnotations, Iterable[clang.cindex.Cursor]]:
|
||||
if not node.spelling and not node.displayname:
|
||||
return (False, None, VlAnnotations(), [])
|
||||
|
||||
@@ -480,8 +468,7 @@ class CallAnnotationsValidator:
|
||||
annotations = VlAnnotations.from_nodes_list(children)
|
||||
return (True, refd, annotations, children)
|
||||
|
||||
def check_mt_safe_call(self, node: clang.cindex.Cursor,
|
||||
refd: clang.cindex.Cursor,
|
||||
def check_mt_safe_call(self, node: clang.cindex.Cursor, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
is_mt_safe = False
|
||||
|
||||
@@ -513,8 +500,7 @@ class CallAnnotationsValidator:
|
||||
# we are calling local method. It is MT safe
|
||||
# only if this method is also only calling local methods or
|
||||
# MT-safe methods
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||
is_mt_safe = True
|
||||
# class/struct member
|
||||
elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced:
|
||||
@@ -525,18 +511,15 @@ class CallAnnotationsValidator:
|
||||
if self.is_constructor_context() and refn.semantic_parent:
|
||||
# we are in constructor, so calling local members is MT_SAFE,
|
||||
# make sure object that we are calling is local to the constructor
|
||||
constructor_class = self._constructor_context[
|
||||
-1].semantic_parent
|
||||
constructor_class = self._constructor_context[-1].semantic_parent
|
||||
if refn.semantic_parent.spelling == constructor_class.spelling:
|
||||
if check_class_member_exists(constructor_class, refn):
|
||||
is_mt_safe = True
|
||||
else:
|
||||
# check if this class inherits from some base class
|
||||
base_class = get_base_class(constructor_class,
|
||||
refn.semantic_parent)
|
||||
base_class = get_base_class(constructor_class, refn.semantic_parent)
|
||||
if base_class:
|
||||
if check_class_member_exists(
|
||||
base_class.get_declaration(), refn):
|
||||
if check_class_member_exists(base_class.get_declaration(), refn):
|
||||
is_mt_safe = True
|
||||
# variable
|
||||
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
|
||||
@@ -567,8 +550,7 @@ class CallAnnotationsValidator:
|
||||
|
||||
# Call handling
|
||||
|
||||
def process_method_call(self, node: clang.cindex.Cursor,
|
||||
refd: clang.cindex.Cursor,
|
||||
def process_method_call(self, node: clang.cindex.Cursor, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
assert self._call_location
|
||||
ctx = self._call_location.annotations
|
||||
@@ -576,58 +558,48 @@ class CallAnnotationsValidator:
|
||||
# MT-safe context
|
||||
if ctx.is_mt_safe_context():
|
||||
if not self.check_mt_safe_call(node, refd, annotations):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
if annotations.is_mt_unsafe_call() or not (
|
||||
annotations.is_stabe_tree_call()
|
||||
or annotations.is_pure_call()
|
||||
annotations.is_stabe_tree_call() or annotations.is_pure_call()
|
||||
or self.check_mt_safe_call(node, refd, annotations)):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call():
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
|
||||
def process_function_call(self, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
def process_function_call(self, refd: clang.cindex.Cursor, annotations: VlAnnotations):
|
||||
assert self._call_location
|
||||
ctx = self._call_location.annotations
|
||||
|
||||
# MT-safe context
|
||||
if ctx.is_mt_safe_context():
|
||||
if not annotations.is_mt_safe_call():
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
if annotations.is_mt_unsafe_call() or not (
|
||||
annotations.is_pure_call()
|
||||
or annotations.is_mt_safe_call()
|
||||
or annotations.is_stabe_tree_call()):
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
if annotations.is_mt_unsafe_call() or not (annotations.is_pure_call()
|
||||
or annotations.is_mt_safe_call()
|
||||
or annotations.is_stabe_tree_call()):
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call():
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
|
||||
def process_constructor_call(self, refd: clang.cindex.Cursor,
|
||||
annotations: VlAnnotations):
|
||||
def process_constructor_call(self, refd: clang.cindex.Cursor, annotations: VlAnnotations):
|
||||
assert self._call_location
|
||||
ctx = self._call_location.annotations
|
||||
|
||||
@@ -635,31 +607,26 @@ class CallAnnotationsValidator:
|
||||
# only if they call local methods or MT-safe functions.
|
||||
if ctx.is_mt_safe_context() or self.is_constructor_context():
|
||||
self._constructor_context.append(refd)
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||
self._constructor_context.pop()
|
||||
|
||||
# stable tree context
|
||||
if ctx.is_stabe_tree_context():
|
||||
self._constructor_context.append(refd)
|
||||
self.iterate_children(refd.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||
self._constructor_context.pop()
|
||||
|
||||
# pure context
|
||||
if ctx.is_pure_context():
|
||||
if not annotations.is_pure_call(
|
||||
) and not refd.is_default_constructor():
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
if not annotations.is_pure_call() and not refd.is_default_constructor():
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||
|
||||
def dispatch_call_node(self, node: clang.cindex.Cursor):
|
||||
[supported, refd, annotations, _] = self.get_referenced_node_info(node)
|
||||
|
||||
if not supported:
|
||||
self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(node.get_children(), self.dispatch_node_inside_definition)
|
||||
return True
|
||||
|
||||
assert refd is not None
|
||||
@@ -676,19 +643,14 @@ class CallAnnotationsValidator:
|
||||
|
||||
assert self._call_location is not None
|
||||
node_file = os.path.abspath(node.location.file.name)
|
||||
self._call_location = self._call_location.copy(file=node_file,
|
||||
line=node.location.line)
|
||||
self._call_location = self._call_location.copy(file=node_file, line=node.location.line)
|
||||
|
||||
# Standalone functions and static class methods
|
||||
if (refd.kind == CursorKind.FUNCTION_DECL
|
||||
or refd.kind == CursorKind.CXX_METHOD
|
||||
and refd.is_static_method()):
|
||||
or refd.kind == CursorKind.CXX_METHOD and refd.is_static_method()):
|
||||
self.process_function_call(refd, annotations)
|
||||
# Function pointer
|
||||
elif refd.kind in [
|
||||
CursorKind.VAR_DECL, CursorKind.FIELD_DECL,
|
||||
CursorKind.PARM_DECL
|
||||
]:
|
||||
elif refd.kind in [CursorKind.VAR_DECL, CursorKind.FIELD_DECL, CursorKind.PARM_DECL]:
|
||||
self.process_function_call(refd, annotations)
|
||||
# Non-static class methods
|
||||
elif refd.kind == CursorKind.CXX_METHOD:
|
||||
@@ -726,18 +688,25 @@ class CallAnnotationsValidator:
|
||||
if self.dispatch_call_node(node) is False:
|
||||
return None
|
||||
elif node.is_definition() and node.kind in [
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
|
||||
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.CONSTRUCTOR,
|
||||
CursorKind.CONVERSION_FUNCTION
|
||||
]:
|
||||
self.process_function_definition(node)
|
||||
return None
|
||||
|
||||
return self.iterate_children(node.get_children(),
|
||||
self.dispatch_node_inside_definition)
|
||||
return self.iterate_children(node.get_children(), self.dispatch_node_inside_definition)
|
||||
|
||||
def process_function_definition(self, node: clang.cindex.Cursor):
|
||||
[supported, refd, annotations, _] = self.get_referenced_node_info(node)
|
||||
|
||||
# Fetch virtual annotations from base class.
|
||||
# Set refd to virtual definition if present.
|
||||
signature = node.displayname
|
||||
if signature in self._base_func_declarations:
|
||||
refd = self._base_func_declarations[signature]
|
||||
virtual_annotations = VlAnnotations.from_nodes_list(refd.get_children())
|
||||
annotations = annotations | virtual_annotations
|
||||
|
||||
if refd and self._is_ignored_def(node, refd):
|
||||
return None
|
||||
|
||||
@@ -752,30 +721,29 @@ class CallAnnotationsValidator:
|
||||
# Implicitly mark definitions in VL_MT_DISABLED_CODE_UNIT .cpp files as
|
||||
# VL_MT_DISABLED. Existence of the annotation on declarations in .h
|
||||
# files is verified below.
|
||||
# Also sets VL_REQUIRES, as this annotation is added together with
|
||||
# Also sets VL_EXCLUDES, as this annotation is added together with
|
||||
# explicit VL_MT_DISABLED.
|
||||
if self.is_mt_disabled_code_unit():
|
||||
if node.location.file.name == self._main_source_file:
|
||||
annotations.mt_disabled = True
|
||||
annotations.requires = True
|
||||
annotations.excludes = True
|
||||
if refd.location.file.name == self._main_source_file:
|
||||
def_annotations.mt_disabled = True
|
||||
def_annotations.requires = True
|
||||
def_annotations.excludes = True
|
||||
|
||||
if not (def_annotations.is_empty() or def_annotations == annotations):
|
||||
if def_annotations != annotations:
|
||||
# Use definition's annotations for the diagnostic
|
||||
# source (i.e. the definition)
|
||||
self._caller = FunctionInfo.from_node(node, refd, def_annotations)
|
||||
self._call_location = self._caller
|
||||
|
||||
self.emit_diagnostic(
|
||||
FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH)
|
||||
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||
DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH)
|
||||
|
||||
# Use concatenation of definition and declaration annotations
|
||||
# for calls validation.
|
||||
self._caller = FunctionInfo.from_node(node, refd,
|
||||
def_annotations | annotations)
|
||||
else:
|
||||
# Use concatenation of definition and declaration annotations
|
||||
# for calls validation.
|
||||
self._caller = FunctionInfo.from_node(node, refd, def_annotations | annotations)
|
||||
prev_call_location = self._call_location
|
||||
self._call_location = self._caller
|
||||
|
||||
@@ -793,8 +761,7 @@ class CallAnnotationsValidator:
|
||||
if declarations:
|
||||
del self._external_decls[usr]
|
||||
|
||||
self.iterate_children(node_children,
|
||||
self.dispatch_node_inside_definition)
|
||||
self.iterate_children(node_children, self.dispatch_node_inside_definition)
|
||||
|
||||
self._call_location = prev_call_location
|
||||
self._caller = prev_call_location
|
||||
@@ -804,25 +771,37 @@ class CallAnnotationsValidator:
|
||||
# Nodes not located inside definition
|
||||
|
||||
def dispatch_node(self, node: clang.cindex.Cursor):
|
||||
if node.kind in [
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
|
||||
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
|
||||
kind = node.kind
|
||||
if kind is CursorKind.CXX_BASE_SPECIFIER:
|
||||
# Get referenced virtual declarations from base class.
|
||||
for base in node.get_children():
|
||||
if base.referenced:
|
||||
for declaration in base.referenced.get_children():
|
||||
self._base_func_declarations[declaration.displayname] = declaration
|
||||
elif kind in [
|
||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.CONSTRUCTOR,
|
||||
CursorKind.CONVERSION_FUNCTION
|
||||
]:
|
||||
if node.is_definition():
|
||||
return self.process_function_definition(node)
|
||||
# else:
|
||||
return self.process_function_declaration(node)
|
||||
|
||||
return self.iterate_children(node.get_children(), self.dispatch_node)
|
||||
result = self.iterate_children(node.get_children(), self.dispatch_node)
|
||||
|
||||
def process_translation_unit(
|
||||
self, translation_unit: clang.cindex.TranslationUnit):
|
||||
# Clean declarations if class declaration processing is finished.
|
||||
if kind in [
|
||||
CursorKind.CLASS_DECL, CursorKind.STRUCT_DECL, CursorKind.UNION_DECL,
|
||||
CursorKind.ENUM_DECL, CursorKind.UNEXPOSED_DECL
|
||||
]:
|
||||
self._base_func_declarations = {}
|
||||
return result
|
||||
|
||||
def process_translation_unit(self, translation_unit: clang.cindex.TranslationUnit):
|
||||
self._level += 1
|
||||
kv_defines = sorted([f"{k}={v}" for k, v in self._defines.items()])
|
||||
concat_defines = '\n'.join(kv_defines)
|
||||
# List of headers already processed in a TU with specified set of defines.
|
||||
tu_processed_headers = self._processed_headers.setdefault(
|
||||
concat_defines, set())
|
||||
tu_processed_headers = self._processed_headers.setdefault(concat_defines, set())
|
||||
for child in translation_unit.cursor.get_children():
|
||||
if self._is_ignored_top_level(child):
|
||||
continue
|
||||
@@ -833,10 +812,8 @@ class CallAnnotationsValidator:
|
||||
self.dispatch_node(child)
|
||||
self._level -= 1
|
||||
|
||||
tu_processed_headers.update([
|
||||
os.path.abspath(str(hdr.source))
|
||||
for hdr in translation_unit.get_includes()
|
||||
])
|
||||
tu_processed_headers.update(
|
||||
[os.path.abspath(str(hdr.source)) for hdr in translation_unit.get_includes()])
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -857,8 +834,7 @@ def get_filter_funcs(verilator_root: str):
|
||||
filename = os.path.abspath(node.location.file.name)
|
||||
return not filename.startswith(verilator_root)
|
||||
|
||||
def is_ignored_def(node: clang.cindex.Cursor,
|
||||
refd: clang.cindex.Cursor) -> bool:
|
||||
def is_ignored_def(node: clang.cindex.Cursor, refd: clang.cindex.Cursor) -> bool:
|
||||
# __*
|
||||
if str(refd.spelling).startswith("__"):
|
||||
return True
|
||||
@@ -901,8 +877,7 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
||||
os.chdir(compile_command.directory)
|
||||
|
||||
index = Index.create()
|
||||
translation_unit = index.parse(compile_command.filename,
|
||||
compile_command.args)
|
||||
translation_unit = index.parse(compile_command.filename, compile_command.args)
|
||||
for diag in translation_unit.diagnostics:
|
||||
if diag.severity >= clang.cindex.Diagnostic.Error:
|
||||
errors.append(str(diag))
|
||||
@@ -910,23 +885,20 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
||||
if len(errors) == 0:
|
||||
pch_file = os.path.join(
|
||||
tmp_dir,
|
||||
f"{compile_command.refid:02}_{os.path.basename(compile_command.filename)}.pch"
|
||||
)
|
||||
f"{compile_command.refid:02}_{os.path.basename(compile_command.filename)}.pch")
|
||||
translation_unit.save(pch_file)
|
||||
|
||||
if pch_file:
|
||||
return pch_file
|
||||
|
||||
except (TranslationUnitSaveError, TranslationUnitLoadError,
|
||||
OSError) as exception:
|
||||
except (TranslationUnitSaveError, TranslationUnitLoadError, OSError) as exception:
|
||||
print(f"%Warning: {exception}", file=sys.stderr)
|
||||
|
||||
finally:
|
||||
os.chdir(initial_cwd)
|
||||
|
||||
print(
|
||||
f"%Warning: Precompilation failed, skipping: {compile_command.filename}",
|
||||
file=sys.stderr)
|
||||
print(f"%Warning: Precompilation failed, skipping: {compile_command.filename}",
|
||||
file=sys.stderr)
|
||||
for error in errors:
|
||||
print(f" {error}", file=sys.stderr)
|
||||
return ""
|
||||
@@ -934,10 +906,8 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
||||
|
||||
# Compile and analyze inputs in a single process.
|
||||
def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
||||
diagnostic_cb: Callable[[Diagnostic],
|
||||
None], verilator_root: str):
|
||||
(is_ignored_top_level, is_ignored_def,
|
||||
is_ignored_call) = get_filter_funcs(verilator_root)
|
||||
diagnostic_cb: Callable[[Diagnostic], None], verilator_root: str):
|
||||
(is_ignored_top_level, is_ignored_def, is_ignored_call) = get_filter_funcs(verilator_root)
|
||||
|
||||
prefix = "verilator_clang_check_attributes_"
|
||||
with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir:
|
||||
@@ -947,8 +917,8 @@ def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
||||
if pch_file:
|
||||
extra_args += ["-include-pch", pch_file]
|
||||
|
||||
cav = CallAnnotationsValidator(diagnostic_cb, is_ignored_top_level,
|
||||
is_ignored_def, is_ignored_call)
|
||||
cav = CallAnnotationsValidator(diagnostic_cb, is_ignored_top_level, is_ignored_def,
|
||||
is_ignored_call)
|
||||
for compile_command in ccl:
|
||||
cav.compile_and_analyze_file(compile_command.filename,
|
||||
extra_args + compile_command.args,
|
||||
@@ -963,12 +933,11 @@ class ParallelAnalysisProcess:
|
||||
|
||||
@staticmethod
|
||||
def init_data(verilator_root: str, tmp_dir: str):
|
||||
(is_ignored_top_level, is_ignored_def,
|
||||
is_ignored_call) = get_filter_funcs(verilator_root)
|
||||
(is_ignored_top_level, is_ignored_def, is_ignored_call) = get_filter_funcs(verilator_root)
|
||||
|
||||
ParallelAnalysisProcess.cav = CallAnnotationsValidator(
|
||||
ParallelAnalysisProcess._diagnostic_handler, is_ignored_top_level,
|
||||
is_ignored_def, is_ignored_call)
|
||||
ParallelAnalysisProcess._diagnostic_handler, is_ignored_top_level, is_ignored_def,
|
||||
is_ignored_call)
|
||||
ParallelAnalysisProcess.tmp_dir = tmp_dir
|
||||
|
||||
@staticmethod
|
||||
@@ -979,31 +948,27 @@ class ParallelAnalysisProcess:
|
||||
def analyze_cpp_file(compile_command: CompileCommand) -> set[Diagnostic]:
|
||||
ParallelAnalysisProcess.diags = set()
|
||||
assert ParallelAnalysisProcess.cav is not None
|
||||
ParallelAnalysisProcess.cav.compile_and_analyze_file(
|
||||
compile_command.filename, compile_command.args,
|
||||
compile_command.directory)
|
||||
ParallelAnalysisProcess.cav.compile_and_analyze_file(compile_command.filename,
|
||||
compile_command.args,
|
||||
compile_command.directory)
|
||||
return ParallelAnalysisProcess.diags
|
||||
|
||||
@staticmethod
|
||||
def precompile_header(compile_command: CompileCommand) -> str:
|
||||
return precompile_header(compile_command,
|
||||
ParallelAnalysisProcess.tmp_dir)
|
||||
return precompile_header(compile_command, ParallelAnalysisProcess.tmp_dir)
|
||||
|
||||
|
||||
# Compile and analyze inputs in multiple processes.
|
||||
def run_parallel_analysis(ccl: Iterable[CompileCommand],
|
||||
pccl: Iterable[CompileCommand],
|
||||
diagnostic_cb: Callable[[Diagnostic], None],
|
||||
jobs_count: int, verilator_root: str):
|
||||
def run_parallel_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
||||
diagnostic_cb: Callable[[Diagnostic],
|
||||
None], jobs_count: int, verilator_root: str):
|
||||
prefix = "verilator_clang_check_attributes_"
|
||||
with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir:
|
||||
with multiprocessing.Pool(
|
||||
processes=jobs_count,
|
||||
initializer=ParallelAnalysisProcess.init_data,
|
||||
initargs=[verilator_root, tmp_dir]) as pool:
|
||||
with multiprocessing.Pool(processes=jobs_count,
|
||||
initializer=ParallelAnalysisProcess.init_data,
|
||||
initargs=[verilator_root, tmp_dir]) as pool:
|
||||
extra_args = []
|
||||
for pch_file in pool.imap_unordered(
|
||||
ParallelAnalysisProcess.precompile_header, pccl):
|
||||
for pch_file in pool.imap_unordered(ParallelAnalysisProcess.precompile_header, pccl):
|
||||
if pch_file:
|
||||
extra_args += ["-include-pch", pch_file]
|
||||
|
||||
@@ -1011,8 +976,7 @@ def run_parallel_analysis(ccl: Iterable[CompileCommand],
|
||||
for compile_command in ccl:
|
||||
compile_command.args = compile_command.args + extra_args
|
||||
|
||||
for diags in pool.imap_unordered(
|
||||
ParallelAnalysisProcess.analyze_cpp_file, ccl, 1):
|
||||
for diags in pool.imap_unordered(ParallelAnalysisProcess.analyze_cpp_file, ccl, 1):
|
||||
for diag in diags:
|
||||
diagnostic_cb(diag)
|
||||
|
||||
@@ -1057,8 +1021,7 @@ class TopDownSummaryPrinter():
|
||||
row_groups: dict[str, list[list[str]]] = {}
|
||||
column_widths = [0, 0]
|
||||
for func in sorted(self._funcs.values(),
|
||||
key=lambda func:
|
||||
(func.info.file, func.info.line, func.info.usr)):
|
||||
key=lambda func: (func.info.file, func.info.line, func.info.usr)):
|
||||
func_info = func.info
|
||||
relfile = os.path.relpath(func_info.file, root_dir)
|
||||
|
||||
@@ -1082,31 +1045,23 @@ class TopDownSummaryPrinter():
|
||||
if func.mismatch:
|
||||
mrelfile = os.path.relpath(func.mismatch.file, root_dir)
|
||||
row_group.append([
|
||||
f"{mrelfile}:{func.mismatch.line}:",
|
||||
f"[{func.mismatch.annotations}]",
|
||||
f"{mrelfile}:{func.mismatch.line}:", f"[{func.mismatch.annotations}]",
|
||||
func.mismatch.name + " [declaration]"
|
||||
])
|
||||
|
||||
row_group.append([
|
||||
f"{relfile}:{func_info.line}:", f"[{func_info.annotations}]",
|
||||
func_info.name
|
||||
])
|
||||
row_group.append(
|
||||
[f"{relfile}:{func_info.line}:", f"[{func_info.annotations}]", func_info.name])
|
||||
|
||||
for callee in sorted(func.calees,
|
||||
key=lambda func:
|
||||
(func.file, func.line, func.usr)):
|
||||
for callee in sorted(func.calees, key=lambda func: (func.file, func.line, func.usr)):
|
||||
crelfile = os.path.relpath(callee.file, root_dir)
|
||||
row_group.append([
|
||||
f"{crelfile}:{callee.line}:", f"[{callee.annotations}]",
|
||||
" " + callee.name
|
||||
])
|
||||
row_group.append(
|
||||
[f"{crelfile}:{callee.line}:", f"[{callee.annotations}]", " " + callee.name])
|
||||
|
||||
row_groups[name] = row_group
|
||||
|
||||
for row in row_group:
|
||||
for row_id, value in enumerate(row[0:-1]):
|
||||
column_widths[row_id] = max(column_widths[row_id],
|
||||
len(value))
|
||||
column_widths[row_id] = max(column_widths[row_id], len(value))
|
||||
|
||||
for label, rows in sorted(row_groups.items(), key=lambda kv: kv[0]):
|
||||
self.begin_group(label)
|
||||
@@ -1114,21 +1069,17 @@ class TopDownSummaryPrinter():
|
||||
print(f"{row[0]:<{column_widths[0]}} "
|
||||
f"{row[1]:<{column_widths[1]}} "
|
||||
f"{row[2]}")
|
||||
print(
|
||||
f"Number of functions reported unsafe: {len(self._unsafe_in_safe)}"
|
||||
)
|
||||
print(f"Number of functions reported unsafe: {len(self._unsafe_in_safe)}")
|
||||
|
||||
|
||||
def main():
|
||||
default_verilator_root = os.path.abspath(
|
||||
os.path.join(os.path.dirname(__file__), ".."))
|
||||
default_verilator_root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""Check function annotations for correctness""",
|
||||
epilog=
|
||||
"""Copyright 2022-2024 by Wilson Snyder. Verilator is free software;
|
||||
epilog="""Copyright 2022-2024 by Wilson Snyder. Verilator 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 Apache License 2.0.
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Apache-2.0""")
|
||||
@@ -1142,29 +1093,23 @@ def main():
|
||||
type=int,
|
||||
default=0,
|
||||
help="Number of parallel jobs to use.")
|
||||
parser.add_argument(
|
||||
"--compile-commands-dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Path to directory containing compile_commands.json.")
|
||||
parser.add_argument("--compile-commands-dir",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Path to directory containing compile_commands.json.")
|
||||
parser.add_argument("--cxxflags",
|
||||
type=str,
|
||||
default=None,
|
||||
help="Extra flags passed to clang++.")
|
||||
parser.add_argument(
|
||||
"--compilation-root",
|
||||
type=str,
|
||||
default=os.getcwd(),
|
||||
help="Directory used as CWD when compiling source files.")
|
||||
parser.add_argument(
|
||||
"-c",
|
||||
"--precompile",
|
||||
action="append",
|
||||
help="Header file to be precompiled and cached at the start.")
|
||||
parser.add_argument("file",
|
||||
parser.add_argument("--compilation-root",
|
||||
type=str,
|
||||
nargs="+",
|
||||
help="Source file to analyze.")
|
||||
default=os.getcwd(),
|
||||
help="Directory used as CWD when compiling source files.")
|
||||
parser.add_argument("-c",
|
||||
"--precompile",
|
||||
action="append",
|
||||
help="Header file to be precompiled and cached at the start.")
|
||||
parser.add_argument("file", type=str, nargs="+", help="Source file to analyze.")
|
||||
|
||||
cmdline = parser.parse_args()
|
||||
|
||||
@@ -1179,8 +1124,7 @@ def main():
|
||||
|
||||
compdb: Optional[CompilationDatabase] = None
|
||||
if cmdline.compile_commands_dir:
|
||||
compdb = CompilationDatabase.fromDirectory(
|
||||
cmdline.compile_commands_dir)
|
||||
compdb = CompilationDatabase.fromDirectory(cmdline.compile_commands_dir)
|
||||
|
||||
if cmdline.cxxflags is not None:
|
||||
common_cxxflags = shlex.split(cmdline.cxxflags)
|
||||
@@ -1230,8 +1174,7 @@ def main():
|
||||
summary_printer.handle_diagnostic, verilator_root)
|
||||
else:
|
||||
run_parallel_analysis(compile_commands_list, precompile_commands_list,
|
||||
summary_printer.handle_diagnostic, cmdline.jobs,
|
||||
verilator_root)
|
||||
summary_printer.handle_diagnostic, cmdline.jobs, verilator_root)
|
||||
|
||||
summary_printer.print_summary(verilator_root)
|
||||
|
||||
|
||||
+41
-51
@@ -58,15 +58,12 @@ def test():
|
||||
if not Args.scenarios or re.match('dist', Args.scenarios):
|
||||
run("make examples VERILATOR_NO_OPT_BUILD=1")
|
||||
run("make test_regress VERILATOR_NO_OPT_BUILD=1" +
|
||||
(" SCENARIOS='" + Args.scenarios +
|
||||
"'" if Args.scenarios else "") +
|
||||
(" DRIVER_HASHSET='--hashset=" + Args.hashset +
|
||||
"'" if Args.hashset else "") +
|
||||
(" SCENARIOS='" + Args.scenarios + "'" if Args.scenarios else "") +
|
||||
(" DRIVER_HASHSET='--hashset=" + Args.hashset + "'" if Args.hashset else "") +
|
||||
('' if Args.stop else ' || true'))
|
||||
else:
|
||||
for test in Args.tests:
|
||||
if not os.path.exists(test) and os.path.exists(
|
||||
"test_regress/t/" + test):
|
||||
if not os.path.exists(test) and os.path.exists("test_regress/t/" + test):
|
||||
test = "test_regress/t/" + test
|
||||
run(test)
|
||||
ci_fold_end()
|
||||
@@ -78,8 +75,7 @@ def test():
|
||||
os.makedirs(cc_dir, exist_ok=True)
|
||||
os.makedirs(cc_dir + "/info", exist_ok=True)
|
||||
|
||||
with subprocess.Popen("find . -print | grep .gcda",
|
||||
shell=True,
|
||||
with subprocess.Popen("find . -print | grep .gcda", shell=True,
|
||||
stdout=subprocess.PIPE) as sp:
|
||||
datout = sp.stdout.read()
|
||||
|
||||
@@ -98,8 +94,7 @@ def test():
|
||||
del dats[dat]
|
||||
break
|
||||
|
||||
with subprocess.Popen("find . -print | grep .gcno",
|
||||
shell=True,
|
||||
with subprocess.Popen("find . -print | grep .gcno", shell=True,
|
||||
stdout=subprocess.PIPE) as sp:
|
||||
datout = sp.stdout.read()
|
||||
|
||||
@@ -116,8 +111,7 @@ def test():
|
||||
if gbase in gcnos:
|
||||
os.symlink(gcnos[gbase], gcno)
|
||||
else:
|
||||
print("MISSING .gcno for a .gcda: " + gcno,
|
||||
file=sys.stderr)
|
||||
print("MISSING .gcno for a .gcda: " + gcno, file=sys.stderr)
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[5]:
|
||||
@@ -142,8 +136,7 @@ def test():
|
||||
if Args.stage_enabled[11]:
|
||||
ci_fold_start("dirs")
|
||||
print("Stage 11: Cleanup paths")
|
||||
cleanup_abs_paths_info(cc_dir, cc_dir + "/app_total.info",
|
||||
cc_dir + "/app_total.info")
|
||||
cleanup_abs_paths_info(cc_dir, cc_dir + "/app_total.info", cc_dir + "/app_total.info")
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[12]:
|
||||
@@ -164,34 +157,38 @@ def test():
|
||||
inc = "--include " + inc
|
||||
if exc != '':
|
||||
exc = "--exclude " + exc
|
||||
run("cd " + cc_dir + " ; " + RealPath +
|
||||
"/fastcov.py -C app_total.info " + inc + " " + exc +
|
||||
" -x --lcov -o app_total_f.info")
|
||||
run("cd " + cc_dir + " ; " + RealPath + "/fastcov.py -C app_total.info " + inc + " " +
|
||||
exc + " -x --lcov -o app_total_f.info")
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[17]:
|
||||
ci_fold_start("report")
|
||||
print("Stage 17: Create HTML")
|
||||
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")
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[18]:
|
||||
ci_fold_start("upload")
|
||||
print("Stage 18: Upload")
|
||||
cmd = "bash <(cat ci/coverage-upload.sh) -f " + cc_dir + "/app_total.info"
|
||||
print("print: Not running: export CODECOV_TOKEN=<hidden>")
|
||||
print("print: Not running: " + cmd)
|
||||
# curl -Os https://cli.codecov.io/latest/linux/codecov ; sudo chmod +x codecov
|
||||
# --disable-search does not seem to work
|
||||
# -d with false directory does not seem to work
|
||||
# So, remove gcno files before calling codecov
|
||||
upload_dir = "nodist/obj_dir/upload"
|
||||
os.makedirs(upload_dir, exist_ok=True)
|
||||
cmd = "ci/codecov -v upload-process -Z" + " -f " + cc_dir + "/app_total.info )"
|
||||
print("print: Not running:")
|
||||
print(" export CODECOV_TOKEN=<hidden>")
|
||||
print(" find . -name '*.gcno' -exec rm {} \\;")
|
||||
print(" " + cmd)
|
||||
ci_fold_end()
|
||||
|
||||
if Args.stage_enabled[19]:
|
||||
print("*-* All Finished *-*")
|
||||
print("")
|
||||
print("* See report in " + cc_dir + "/html/index.html")
|
||||
print(
|
||||
"* Remember to make distclean && ./configure before working on non-coverage"
|
||||
)
|
||||
print("* Remember to make distclean && ./configure before working on non-coverage")
|
||||
|
||||
|
||||
def clone_sources(cc_dir):
|
||||
@@ -200,9 +197,8 @@ def clone_sources(cc_dir):
|
||||
for globf in Source_Globs:
|
||||
for infile in glob.glob(globf):
|
||||
if re.match(r'^/', infile):
|
||||
sys.exit(
|
||||
"%Error: source globs should be relative not absolute filenames, "
|
||||
+ infile)
|
||||
sys.exit("%Error: source globs should be relative not absolute filenames, " +
|
||||
infile)
|
||||
outfile = cc_dir + "/" + infile
|
||||
outpath = re.sub(r'/[^/]*$', '', outfile, count=1)
|
||||
os.makedirs(outpath, exist_ok=True)
|
||||
@@ -243,22 +239,20 @@ def clone_sources(cc_dir):
|
||||
done = True
|
||||
|
||||
ofh.write(line + "\n")
|
||||
print("Number of source lines automatically LCOV_EXCL_LINE'ed: %d" %
|
||||
excluded_lines)
|
||||
print("Number of source lines automatically LCOV_EXCL_BR_LINE'ed: %d" %
|
||||
excluded_br_lines)
|
||||
print("Number of source lines automatically LCOV_EXCL_LINE'ed: %d" % excluded_lines)
|
||||
print("Number of source lines automatically LCOV_EXCL_BR_LINE'ed: %d" % excluded_br_lines)
|
||||
|
||||
|
||||
def cleanup_abs_paths_info(cc_dir, infile, outfile):
|
||||
lines = []
|
||||
with open(infile, "r", encoding="utf8") as fh:
|
||||
for line in fh:
|
||||
if re.search(r'^SF:', line):
|
||||
line = re.sub(os.environ['VERILATOR_ROOT'] + '/',
|
||||
'',
|
||||
line,
|
||||
count=1)
|
||||
if re.search(r'^SF:', line) and not re.search(r'^SF:/usr/', line):
|
||||
line = re.sub(os.environ['VERILATOR_ROOT'] + '/', '', line, count=1)
|
||||
line = re.sub(cc_dir + '/', '', line, count=1)
|
||||
line = re.sub(r'^SF:.*?/include/', 'SF:include/', line, count=1)
|
||||
line = re.sub(r'^SF:.*?/src/', 'SF:src/', line, count=1)
|
||||
line = re.sub(r'^SF:.*?/test_regress/', 'SF:test_regress/', line, count=1)
|
||||
line = re.sub(r'obj_dbg/verilog.y$', 'verilog.y', line)
|
||||
# print("Remaining SF: "+line)
|
||||
lines.append(line)
|
||||
@@ -340,15 +334,13 @@ def ci_fold_end():
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=
|
||||
"""code_coverage builds Verilator with C++ coverage support and runs
|
||||
description="""code_coverage builds Verilator with C++ coverage support and runs
|
||||
tests with coverage enabled. This will rebuild the current object
|
||||
files. Run as:
|
||||
|
||||
cd $VERILATOR_ROOT
|
||||
nodist/code_coverage""",
|
||||
epilog=
|
||||
"""Copyright 2019-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2019-2024 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.
|
||||
@@ -358,22 +350,20 @@ SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||
parser.add_argument('--debug', action='store_true', help='enable debug')
|
||||
parser.add_argument('--hashset',
|
||||
action='store',
|
||||
help='pass test hashset onto driver.pl test harness')
|
||||
help='pass test hashset onto driver.py test harness')
|
||||
parser.add_argument('--scenarios',
|
||||
action='store',
|
||||
help='pass test scenarios onto driver.pl test harness')
|
||||
parser.add_argument(
|
||||
'--stages',
|
||||
action='store',
|
||||
help='runs a specific stage or range of stages (see the script)')
|
||||
help='pass test scenarios onto driver.py test harness')
|
||||
parser.add_argument('--stages',
|
||||
'--stage',
|
||||
action='store',
|
||||
help='runs a specific stage or range of stages (see the script)')
|
||||
parser.add_argument(
|
||||
'--tests',
|
||||
'--test',
|
||||
action='append',
|
||||
dest='tests',
|
||||
default=[],
|
||||
help=
|
||||
'Instead of normal regressions, run the specified test(s), may be used multiple times'
|
||||
)
|
||||
help='Instead of normal regressions, run the specified test(s), may be used multiple times')
|
||||
parser.add_argument('--no-stop',
|
||||
dest='stop',
|
||||
action='store_false',
|
||||
|
||||
+10
-21
@@ -20,8 +20,7 @@ def dotread(filename):
|
||||
vnum = 0
|
||||
|
||||
vertex_re = re.compile(r'^\t([a-zA-Z0-9_]+)\t(.*)$')
|
||||
edge_re = re.compile(
|
||||
r'^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s*(.*)$')
|
||||
edge_re = re.compile(r'^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s*(.*)$')
|
||||
|
||||
for line in fh:
|
||||
vertex_match = re.search(vertex_re, line)
|
||||
@@ -29,11 +28,7 @@ def dotread(filename):
|
||||
if vertex_match:
|
||||
if vertex_match.group(1) != 'nTITLE':
|
||||
header = False
|
||||
Vertexes.append({
|
||||
'num': vnum,
|
||||
'line': line,
|
||||
'name': vertex_match.group(1)
|
||||
})
|
||||
Vertexes.append({'num': vnum, 'line': line, 'name': vertex_match.group(1)})
|
||||
vnum += 1
|
||||
elif edge_match:
|
||||
fromv = edge_match.group(1)
|
||||
@@ -65,14 +60,13 @@ def cwrite(filename):
|
||||
fh.write("void V3GraphTestImport::dotImport() {\n")
|
||||
fh.write(" auto* gp = &m_graph;\n")
|
||||
for ver in sorted(Vertexes, key=lambda ver: ver['num']):
|
||||
fh.write(
|
||||
" auto* %s = new V3GraphTestVertex{gp, \"%s\"}; if (%s) {}\n"
|
||||
% (ver['name'], ver['name'], ver['name']))
|
||||
fh.write(" auto* %s = new V3GraphTestVertex{gp, \"%s\"}; if (%s) {}\n" %
|
||||
(ver['name'], ver['name'], ver['name']))
|
||||
fh.write("\n")
|
||||
for edge in Edges:
|
||||
fh.write(" new V3GraphEdge{gp, %s, %s, %s, %s};\n" %
|
||||
(edge['from'], edge['to'], edge['weight'],
|
||||
"true" if edge['cutable'] else "false"))
|
||||
fh.write(
|
||||
" new V3GraphEdge{gp, %s, %s, %s, %s};\n" %
|
||||
(edge['from'], edge['to'], edge['weight'], "true" if edge['cutable'] else "false"))
|
||||
fh.write("}\n")
|
||||
|
||||
|
||||
@@ -82,22 +76,17 @@ def cwrite(filename):
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=
|
||||
"""dot_importer takes a graphvis .dot file and converts into .cpp file.
|
||||
description="""dot_importer takes a graphvis .dot file and converts into .cpp file.
|
||||
This x.cpp file is then manually included in V3GraphTest.cpp to verify
|
||||
various xsub-algorithms.""",
|
||||
epilog=
|
||||
"""Copyright 2005-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2005-2024 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""")
|
||||
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('filename', help='input .dot filename to process')
|
||||
|
||||
Args = parser.parse_args()
|
||||
|
||||
+374
-49
@@ -18,20 +18,21 @@
|
||||
$ ./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 fnmatch
|
||||
import logging
|
||||
import argparse
|
||||
import threading
|
||||
import subprocess
|
||||
import multiprocessing
|
||||
from pathlib import Path
|
||||
|
||||
FASTCOV_VERSION = (1,7)
|
||||
FASTCOV_VERSION = (1,15)
|
||||
MINIMUM_PYTHON = (3,5)
|
||||
MINIMUM_GCOV = (9,0,0)
|
||||
|
||||
@@ -40,6 +41,10 @@ START_TIME = time.monotonic()
|
||||
GCOVS_TOTAL = 0
|
||||
GCOVS_SKIPPED = 0
|
||||
|
||||
# Gcov Coverage File Extensions
|
||||
GCOV_GCNO_EXT = ".gcno" # gcno = "[gc]ov [no]te"
|
||||
GCOV_GCDA_EXT = ".gcda" # gcda = "[gc]ov [da]ta"
|
||||
|
||||
# For when things go wrong...
|
||||
# Start error codes at 3 because 1-2 are special
|
||||
# See https://stackoverflow.com/a/1535733/2516916
|
||||
@@ -49,6 +54,8 @@ EXIT_CODES = {
|
||||
"python_version": 4,
|
||||
"unsupported_coverage_format": 5,
|
||||
"excl_not_found": 6,
|
||||
"bad_chunk_file": 7,
|
||||
"missing_json_key": 8,
|
||||
}
|
||||
|
||||
# Disable all logging in case developers are using this as a module
|
||||
@@ -60,6 +67,132 @@ class FastcovFormatter(logging.Formatter):
|
||||
log_message = super(FastcovFormatter, self).format(record)
|
||||
return "[{:.3f}s] {}".format(stopwatch(), log_message)
|
||||
|
||||
class DiffParseError(Exception):
|
||||
pass
|
||||
|
||||
class DiffParser(object):
|
||||
def _refinePaths(self, diff_metadata, diff_base_dir):
|
||||
diff_metadata.pop('/dev/null', None)
|
||||
diff_metadata.pop('', None)
|
||||
for key, value in diff_metadata.copy().items():
|
||||
diff_metadata.pop(key)
|
||||
#sources without added lines will be excluded
|
||||
if value:
|
||||
newpath = os.path.join(diff_base_dir, key) if diff_base_dir else os.path.abspath(key)
|
||||
diff_metadata[newpath] = value
|
||||
|
||||
def _parseTargetFile(self, line_with_target_file):
|
||||
#f.e. '+++ b/README.md1' or '+++ b/README.md1 timestamp'
|
||||
target_source = line_with_target_file[4:].partition('\t')[0].strip()
|
||||
target_source = target_source[2:] if target_source.startswith('b/') else target_source
|
||||
return target_source
|
||||
|
||||
def _parseHunkBoundaries(self, line_with_hunk_boundaries, line_index):
|
||||
#f.e. '@@ -121,4 +122,4 @@ Time to process all gcda and parse all gcov:'
|
||||
# Here ['-121,4', '+122,4']
|
||||
lines_info = line_with_hunk_boundaries[3:].partition("@@")[0].strip().split(' ')
|
||||
if len(lines_info) != 2:
|
||||
raise DiffParseError("Found invalid hunk. Line #{}. {}".format(line_index, line_with_hunk_boundaries))
|
||||
# Here ['122','4']
|
||||
target_lines_info = lines_info[1].strip('+').partition(',')
|
||||
target_line_current = int(target_lines_info[0])
|
||||
target_lines_count = int(target_lines_info[2]) if target_lines_info[2] else 1
|
||||
|
||||
# Here ['121','4']
|
||||
source_lines_info = lines_info[0].strip('-').partition(',')
|
||||
source_line_current = int(source_lines_info[0])
|
||||
source_lines_count = int(source_lines_info[2]) if source_lines_info[2] else 1
|
||||
return target_line_current, target_lines_count, source_line_current, source_lines_count
|
||||
|
||||
def parseDiffFile(self, diff_file, diff_base_dir, fallback_encodings=[]):
|
||||
diff_metadata = {}
|
||||
target_source = None
|
||||
target_hunk = set()
|
||||
target_line_current = 0
|
||||
target_line_end = 0
|
||||
source_line_current = 0
|
||||
source_line_end = 0
|
||||
found_hunk = False
|
||||
for i, line in enumerate(getSourceLines(diff_file, fallback_encodings), 1):
|
||||
line = line.rstrip()
|
||||
if not found_hunk:
|
||||
if line.startswith('+++ '):
|
||||
# refresh file
|
||||
target_source = self._parseTargetFile(line)
|
||||
elif line.startswith('@@ '):
|
||||
# refresh hunk
|
||||
target_line_current, target_lines_count, source_line_current, source_lines_count = self._parseHunkBoundaries(line, i)
|
||||
target_line_end = target_line_current + target_lines_count
|
||||
source_line_end = source_line_current + source_lines_count
|
||||
target_hunk = set()
|
||||
found_hunk = True
|
||||
continue
|
||||
if target_line_current > target_line_end or source_line_current > source_line_end:
|
||||
raise DiffParseError("Hunk longer than expected. Line #{}. {}".format(i, line))
|
||||
|
||||
if line.startswith('+'):
|
||||
#line related to target
|
||||
target_hunk.add(target_line_current)
|
||||
target_line_current = target_line_current + 1
|
||||
elif line.startswith(' ') or line == '':
|
||||
# line related to both
|
||||
target_line_current = target_line_current + 1
|
||||
source_line_current = source_line_current + 1
|
||||
elif line.startswith('-'):
|
||||
# line related to source
|
||||
source_line_current = source_line_current + 1
|
||||
elif not line.startswith('\\'): # No newline at end of file
|
||||
# line with newline marker is not included into any boundaries
|
||||
raise DiffParseError("Found unrecognized hunk line type. Line #{}. {}".format(i, line))
|
||||
|
||||
if target_line_current == target_line_end and source_line_current == source_line_end:
|
||||
# Checked all lines, save data
|
||||
if target_source in diff_metadata:
|
||||
diff_metadata[target_source] = target_hunk.union(diff_metadata[target_source])
|
||||
else:
|
||||
diff_metadata[target_source] = target_hunk
|
||||
target_hunk = set()
|
||||
found_hunk = False
|
||||
|
||||
if target_line_current != target_line_end or source_line_current != source_line_end:
|
||||
raise DiffParseError("Unexpected end of file. Expected hunk with {} target lines, {} source lines".format(
|
||||
target_line_end - target_line_current, source_line_end - source_line_current))
|
||||
|
||||
self._refinePaths(diff_metadata, diff_base_dir)
|
||||
return diff_metadata
|
||||
|
||||
def filterByDiff(self, diff_file, dir_base_dir, fastcov_json, fallback_encodings=[]):
|
||||
diff_metadata = self.parseDiffFile(diff_file, dir_base_dir, fallback_encodings)
|
||||
logging.debug("Include only next files: {}".format(diff_metadata.keys()))
|
||||
excluded_files_count = 0
|
||||
excluded_lines_count = 0
|
||||
for source in list(fastcov_json["sources"].keys()):
|
||||
diff_lines = diff_metadata.get(source, None)
|
||||
if not diff_lines:
|
||||
excluded_files_count = excluded_files_count + 1
|
||||
logging.debug("Exclude {} according to diff file".format(source))
|
||||
fastcov_json["sources"].pop(source)
|
||||
continue
|
||||
for test_name, report_data in fastcov_json["sources"][source].copy().items():
|
||||
#No info about functions boundaries, removing all
|
||||
for function in list(report_data["functions"].keys()):
|
||||
report_data["functions"].pop(function, None)
|
||||
for line in list(report_data["lines"].keys()):
|
||||
if line not in diff_lines:
|
||||
excluded_lines_count = excluded_lines_count + 1
|
||||
report_data["lines"].pop(line)
|
||||
for branch_line in list(report_data["branches"].keys()):
|
||||
if branch_line not in diff_lines:
|
||||
report_data["branches"].pop(branch_line)
|
||||
if len(report_data["lines"]) == 0:
|
||||
fastcov_json["sources"][source].pop(test_name)
|
||||
if len(fastcov_json["sources"][source]) == 0:
|
||||
excluded_files_count = excluded_files_count + 1
|
||||
logging.debug('Exclude {} file as it has no lines due to diff filter'.format(source))
|
||||
fastcov_json["sources"].pop(source)
|
||||
logging.info("Excluded {} files and {} lines according to diff file".format(excluded_files_count, excluded_lines_count))
|
||||
return fastcov_json
|
||||
|
||||
def chunks(l, n):
|
||||
"""Yield successive n-sized chunks from l."""
|
||||
for i in range(0, len(l), n):
|
||||
@@ -69,6 +202,10 @@ def setExitCode(key):
|
||||
global EXIT_CODE
|
||||
EXIT_CODE = EXIT_CODES[key]
|
||||
|
||||
def setExitCodeRaw(code):
|
||||
global EXIT_CODE
|
||||
EXIT_CODE = code
|
||||
|
||||
def incrementCounters(total, skipped):
|
||||
global GCOVS_TOTAL
|
||||
global GCOVS_SKIPPED
|
||||
@@ -98,10 +235,48 @@ def getGcovVersion(gcov):
|
||||
p.wait()
|
||||
return parseVersionFromLine(output.split("\n")[0])
|
||||
|
||||
def tryParseNumber(s):
|
||||
try:
|
||||
return int(s)
|
||||
except ValueError:
|
||||
# Log a warning if not hyphen
|
||||
if s != "-":
|
||||
logging.warning("Unsupported numerical value '%s', using 0", s)
|
||||
|
||||
# Default to 0 if we can't parse the number (e.g. "-", "NaN", etc.)
|
||||
return 0
|
||||
|
||||
def removeFiles(files):
|
||||
for file in files:
|
||||
os.remove(file)
|
||||
|
||||
def processPrefix(path, prefix, prefix_strip):
|
||||
p = Path(path)
|
||||
if p.exists() or not p.is_absolute():
|
||||
return path
|
||||
|
||||
if prefix_strip > 0:
|
||||
segments = p.parts
|
||||
|
||||
if len(segments) < prefix_strip + 1:
|
||||
logging.warning("Couldn't strip %i path levels from %s.", prefix_strip, path)
|
||||
return path
|
||||
|
||||
segments = segments[prefix_strip+1:]
|
||||
p = Path(segments[0])
|
||||
segments = segments[1:]
|
||||
for s in segments:
|
||||
p = p.joinpath(s)
|
||||
|
||||
if len(prefix) > 0:
|
||||
if p.is_absolute():
|
||||
p = Path(prefix).joinpath(p.relative_to('/'))
|
||||
else:
|
||||
p = Path(prefix).joinpath(p)
|
||||
|
||||
return str(p)
|
||||
|
||||
|
||||
def getFilteredCoverageFiles(coverage_files, exclude):
|
||||
def excludeGcda(gcda):
|
||||
for ex in exclude:
|
||||
@@ -111,11 +286,16 @@ def getFilteredCoverageFiles(coverage_files, exclude):
|
||||
return True
|
||||
return list(filter(excludeGcda, coverage_files))
|
||||
|
||||
def globCoverageFiles(cwd, coverage_type):
|
||||
return glob.glob(os.path.join(os.path.abspath(cwd), "**/*" + coverage_type), recursive=True)
|
||||
|
||||
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)
|
||||
# gcov strips off extension of whatever you pass it and searches [extensionless name] + .gcno/.gcda
|
||||
# We should pass either gcno or gcda, but not both - if you pass both it will be processed twice
|
||||
coverage_type = GCOV_GCNO_EXT if use_gcno else GCOV_GCDA_EXT
|
||||
coverage_files = globCoverageFiles(cwd, coverage_type)
|
||||
|
||||
logging.info("Found {} coverage files ({})".format(len(coverage_files), coverage_type))
|
||||
logging.debug("Coverage files found:\n %s", "\n ".join(coverage_files))
|
||||
@@ -125,15 +305,32 @@ def gcovWorker(data_q, metrics_q, args, chunk, gcov_filter_options):
|
||||
base_report = {"sources": {}}
|
||||
gcovs_total = 0
|
||||
gcovs_skipped = 0
|
||||
error_exit = False
|
||||
|
||||
gcov_args = "-it"
|
||||
gcov_bin = args.gcov
|
||||
gcov_args = ["--json-format", "--stdout"]
|
||||
if args.branchcoverage or args.xbranchcoverage:
|
||||
gcov_args += "b"
|
||||
gcov_args.append("--branch-probabilities")
|
||||
|
||||
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)
|
||||
encoding = sys.stdout.encoding if sys.stdout.encoding else 'UTF-8'
|
||||
workdir = args.cdirectory if args.cdirectory else "."
|
||||
|
||||
p = subprocess.Popen([gcov_bin] + gcov_args + chunk, cwd=workdir, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||
for i, line in enumerate(iter(p.stdout.readline, b'')):
|
||||
try:
|
||||
intermediate_json = json.loads(line.decode(encoding))
|
||||
except json.decoder.JSONDecodeError as e:
|
||||
logging.error("Could not process chunk file '{}' ({}/{})".format(chunk[i], i+1, len(chunk)))
|
||||
logging.error(str(e))
|
||||
setExitCode("bad_chunk_file")
|
||||
continue
|
||||
|
||||
if "current_working_directory" not in intermediate_json:
|
||||
logging.error("Missing 'current_working_directory' for data file: {}".format(intermediate_json))
|
||||
setExitCode("missing_json_key")
|
||||
continue
|
||||
|
||||
intermediate_json_files = processGcovs(args.cdirectory, intermediate_json["files"], intermediate_json["current_working_directory"], 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"])
|
||||
@@ -143,6 +340,8 @@ def gcovWorker(data_q, metrics_q, args, chunk, gcov_filter_options):
|
||||
data_q.put(base_report)
|
||||
metrics_q.put((gcovs_total, gcovs_skipped))
|
||||
|
||||
sys.exit(EXIT_CODE)
|
||||
|
||||
def processGcdas(args, coverage_files, gcov_filter_options):
|
||||
chunk_size = max(args.minimum_chunk, int(len(coverage_files) / args.jobs) + 1)
|
||||
|
||||
@@ -163,6 +362,8 @@ def processGcdas(args, coverage_files, gcov_filter_options):
|
||||
|
||||
for p in processes:
|
||||
p.join()
|
||||
if p.exitcode != 0:
|
||||
setExitCodeRaw(p.exitcode)
|
||||
|
||||
base_fastcov = fastcov_jsons.pop()
|
||||
for fj in fastcov_jsons:
|
||||
@@ -184,6 +385,12 @@ def shouldFilterSource(source, gcov_filter_options):
|
||||
logging.debug("Filtering coverage for '%s' due to option '--exclude %s'", source, ex)
|
||||
return True
|
||||
|
||||
# Check exclude filter
|
||||
for ex_glob in gcov_filter_options["exclude_glob"]:
|
||||
if fnmatch.fnmatch(source, ex_glob):
|
||||
logging.debug("Filtering coverage for '%s' due to option '--exclude-glob %s'", source, ex_glob)
|
||||
return True
|
||||
|
||||
# Check include filter
|
||||
if gcov_filter_options["include"]:
|
||||
included = False
|
||||
@@ -205,9 +412,12 @@ def filterFastcov(fastcov_json, args):
|
||||
if shouldFilterSource(source, gcov_filter_options):
|
||||
del fastcov_json["sources"][source]
|
||||
|
||||
def processGcov(cwd, gcov, files, gcov_filter_options):
|
||||
def processGcov(cwd, gcov, source_base_dir, files, gcov_filter_options):
|
||||
# Uses cwd if set, else source_base_dir from gcov json. If both are empty, uses "."
|
||||
base_dir = cwd if cwd else source_base_dir
|
||||
base_dir = base_dir if base_dir else "."
|
||||
# Add absolute path
|
||||
gcov["file_abs"] = os.path.abspath(os.path.join(cwd, gcov["file"]))
|
||||
gcov["file_abs"] = os.path.abspath(os.path.join(base_dir, gcov["file"]))
|
||||
|
||||
if shouldFilterSource(gcov["file_abs"], gcov_filter_options):
|
||||
return
|
||||
@@ -215,10 +425,10 @@ def processGcov(cwd, gcov, files, gcov_filter_options):
|
||||
files.append(gcov)
|
||||
logging.debug("Accepted coverage for '%s'", gcov["file_abs"])
|
||||
|
||||
def processGcovs(cwd, gcov_files, gcov_filter_options):
|
||||
def processGcovs(cwd, gcov_files, source_base_dir, gcov_filter_options):
|
||||
files = []
|
||||
for gcov in gcov_files:
|
||||
processGcov(cwd, gcov, files, gcov_filter_options)
|
||||
processGcov(cwd, gcov, source_base_dir, files, gcov_filter_options)
|
||||
return files
|
||||
|
||||
def dumpBranchCoverageToLcovInfo(f, branches):
|
||||
@@ -288,15 +498,44 @@ def getSourceLines(source, 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):
|
||||
def containsMarker(markers, strBody):
|
||||
for marker in markers:
|
||||
if marker in strBody:
|
||||
return True
|
||||
return False
|
||||
|
||||
# Returns whether source coverage changed or not
|
||||
def exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, exclude_line_marker, fallback_encodings, gcov_prefix, gcov_prefix_strip):
|
||||
source_to_open = processPrefix(source, gcov_prefix, gcov_prefix_strip)
|
||||
|
||||
# Before doing any work, check if this file even needs to be processed
|
||||
if not exclude_branches_sw and not include_branches_sw:
|
||||
# Ignore unencodable characters
|
||||
with open(source_to_open, errors="ignore") as f:
|
||||
if not containsMarker(exclude_line_marker + ["LCOV_EXCL"], f.read()):
|
||||
return False
|
||||
|
||||
# If we've made it this far we have to check every line
|
||||
|
||||
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):
|
||||
for i, line in enumerate(getSourceLines(source_to_open, fallback_encodings), 1):
|
||||
# Cycle through test names (likely only 1)
|
||||
for test_name in fastcov_sources[source]:
|
||||
fastcov_data = fastcov_sources[source][test_name]
|
||||
|
||||
# Check if branch coverage should be deleted based on CLI options
|
||||
if (exclude_branches_sw or include_branches_sw) and (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]
|
||||
|
||||
# Skip to next line as soon as possible
|
||||
if not containsMarker(exclude_line_marker + ["LCOV_EXCL"], line):
|
||||
continue
|
||||
|
||||
# Build line to function dict so can quickly delete by line number
|
||||
line_to_func = {}
|
||||
for f in fastcov_data["functions"].keys():
|
||||
@@ -305,16 +544,7 @@ def exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_bran
|
||||
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:
|
||||
if any(marker in line for marker in exclude_line_marker):
|
||||
for key in ["lines", "branches"]:
|
||||
if i in fastcov_data[key]:
|
||||
del fastcov_data[key][i]
|
||||
@@ -347,26 +577,56 @@ def exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_bran
|
||||
if i in fastcov_data["branches"]:
|
||||
del fastcov_data["branches"][i]
|
||||
|
||||
def exclMarkerWorker(fastcov_sources, chunk, exclude_branches_sw, include_branches_sw, fallback_encodings):
|
||||
# Source coverage changed
|
||||
return True
|
||||
|
||||
def exclMarkerWorker(data_q, fastcov_sources, chunk, exclude_branches_sw, include_branches_sw, exclude_line_marker, fallback_encodings, gcov_prefix, gcov_prefix_strip):
|
||||
changed_sources = []
|
||||
|
||||
for source in chunk:
|
||||
try:
|
||||
exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings)
|
||||
if exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, exclude_line_marker, fallback_encodings, gcov_prefix, gcov_prefix_strip):
|
||||
changed_sources.append((source, fastcov_sources[source]))
|
||||
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):
|
||||
# Write out changed sources back to main fastcov file
|
||||
data_q.put(changed_sources)
|
||||
|
||||
# Exit current process with appropriate code
|
||||
sys.exit(EXIT_CODE)
|
||||
|
||||
def processExclusionMarkers(fastcov_json, jobs, exclude_branches_sw, include_branches_sw, exclude_line_marker, min_chunk_size, fallback_encodings, gcov_prefix, gcov_prefix_strip):
|
||||
chunk_size = max(min_chunk_size, int(len(fastcov_json["sources"]) / jobs) + 1)
|
||||
|
||||
threads = []
|
||||
processes = []
|
||||
data_q = multiprocessing.Queue()
|
||||
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()
|
||||
p = multiprocessing.Process(target=exclMarkerWorker, args=(data_q, fastcov_json["sources"], chunk, exclude_branches_sw, include_branches_sw, exclude_line_marker, fallback_encodings, gcov_prefix, gcov_prefix_strip))
|
||||
processes.append(p)
|
||||
p.start()
|
||||
|
||||
logging.info("Spawned {} threads each scanning at most {} source files".format(len(threads), chunk_size))
|
||||
for t in threads:
|
||||
t.join()
|
||||
logging.info("Spawned {} exclusion marker scanning processes, each processing at most {} source files".format(len(processes), chunk_size))
|
||||
|
||||
changed_sources = []
|
||||
for p in processes:
|
||||
changed_sources += data_q.get()
|
||||
|
||||
for p in processes:
|
||||
p.join()
|
||||
if p.exitcode != 0:
|
||||
setExitCodeRaw(p.exitcode)
|
||||
|
||||
for changed_source in changed_sources:
|
||||
fastcov_json["sources"][changed_source[0]] = changed_source[1]
|
||||
|
||||
def validateSources(fastcov_json, gcov_prefix, gcov_prefix_strip):
|
||||
logging.info("Checking if all sources exist")
|
||||
for source in fastcov_json["sources"].keys():
|
||||
source = processPrefix(source, gcov_prefix, gcov_prefix_strip)
|
||||
if not os.path.exists(source):
|
||||
logging.error("Cannot find '{}'".format(source))
|
||||
|
||||
def distillFunction(function_raw, functions):
|
||||
function_name = function_raw["name"]
|
||||
@@ -413,6 +673,13 @@ def filterExceptionalBranches(branches):
|
||||
def distillLine(line_raw, lines, branches, include_exceptional_branches):
|
||||
line_number = int(line_raw["line_number"])
|
||||
count = int(line_raw["count"])
|
||||
if count < 0:
|
||||
if "function_name" in line_raw:
|
||||
logging.warning("Ignoring negative count found in '%s'.", line_raw["function_name"])
|
||||
else:
|
||||
logging.warning("Ignoring negative count.")
|
||||
count = 0
|
||||
|
||||
if line_number not in lines:
|
||||
lines[line_number] = count
|
||||
else:
|
||||
@@ -458,6 +725,7 @@ def getGcovFilterOptions(args):
|
||||
"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,
|
||||
"exclude_glob":args.excludepost_glob
|
||||
}
|
||||
|
||||
def addDicts(dict1, dict2):
|
||||
@@ -529,30 +797,30 @@ def parseInfo(path):
|
||||
current_test_name = line[3:].strip()
|
||||
elif line.startswith("SF:"):
|
||||
current_sf = line[3:].strip()
|
||||
fastcov_json["sources"][current_sf] = {
|
||||
fastcov_json["sources"].setdefault(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)
|
||||
current_data["functions"][function_name]["start_line"] = tryParseNumber(line_num)
|
||||
elif line.startswith("FNDA:"):
|
||||
count, function_name = line[5:].strip().split(",")
|
||||
current_data["functions"][function_name]["execution_count"] = int(count)
|
||||
current_data["functions"][function_name]["execution_count"] = tryParseNumber(count)
|
||||
elif line.startswith("DA:"):
|
||||
line_num, count = line[3:].strip().split(",")
|
||||
current_data["lines"][line_num] = int(count)
|
||||
current_data["lines"][line_num] = tryParseNumber(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))
|
||||
current_data["branches"][line_num].append(tryParseNumber(count))
|
||||
|
||||
return fastcov_json
|
||||
|
||||
@@ -610,9 +878,9 @@ def getGcovCoverage(args):
|
||||
coverage_files = getFilteredCoverageFiles(coverage_files, args.excludepre)
|
||||
logging.info("Found {} coverage files after filtering".format(len(coverage_files)))
|
||||
|
||||
# We "zero" the "counters" by deleting all gcda files
|
||||
# We "zero" the "counters" by simply deleting all gcda files
|
||||
if args.zerocounters:
|
||||
removeFiles(coverage_files)
|
||||
removeFiles(globCoverageFiles(args.directory, GCOV_GCDA_EXT))
|
||||
logging.info("Removed {} .gcda files".format(len(coverage_files)))
|
||||
sys.exit()
|
||||
|
||||
@@ -626,6 +894,37 @@ def getGcovCoverage(args):
|
||||
|
||||
return fastcov_json
|
||||
|
||||
def formatCoveredItems(covered, total):
|
||||
coverage = (covered * 100.0) / total if total > 0 else 100.0
|
||||
coverage = round(coverage, 2)
|
||||
return "{:.2f}%, {}/{}".format(coverage, covered, total)
|
||||
|
||||
def dumpStatistic(fastcov_json):
|
||||
total_lines = 0
|
||||
covered_lines = 0
|
||||
total_functions = 0
|
||||
covered_functions = 0
|
||||
total_files = len(fastcov_json["sources"])
|
||||
covered_files = 0
|
||||
|
||||
for source_name, source in fastcov_json["sources"].items():
|
||||
is_file_covered = False
|
||||
for test_name, test in source.items():
|
||||
total_lines += len(test["lines"])
|
||||
for execution_count in test["lines"].values():
|
||||
covered_lines += 1 if execution_count > 0 else 0
|
||||
is_file_covered = is_file_covered or execution_count > 0
|
||||
total_functions += len(test["functions"])
|
||||
for function in test["functions"].values():
|
||||
covered_functions += 1 if function['execution_count'] > 0 else 0
|
||||
is_file_covered = is_file_covered or function['execution_count'] > 0
|
||||
if is_file_covered:
|
||||
covered_files = covered_files + 1
|
||||
|
||||
logging.info("Files Coverage: {}".format(formatCoveredItems(covered_files, total_files)))
|
||||
logging.info("Functions Coverage: {}".format(formatCoveredItems(covered_functions, total_functions)))
|
||||
logging.info("Lines Coverage: {}".format(formatCoveredItems(covered_lines, total_lines)))
|
||||
|
||||
def dumpFile(fastcov_json, args):
|
||||
if args.lcov:
|
||||
dumpToLcovInfo(fastcov_json, args.output)
|
||||
@@ -634,6 +933,9 @@ def dumpFile(fastcov_json, args):
|
||||
dumpToJson(fastcov_json, args.output)
|
||||
logging.info("Created fastcov json file '{}'".format(args.output))
|
||||
|
||||
if args.dump_statistic:
|
||||
dumpStatistic(fastcov_json)
|
||||
|
||||
def tupleToDotted(tup):
|
||||
return ".".join(map(str, tup))
|
||||
|
||||
@@ -655,15 +957,19 @@ def parseArgs():
|
||||
# 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('-eg', '--exclude-glob', dest='excludepost_glob', nargs="+", metavar='', default=[], help='Filter: Exclude source files by glob pattern 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('-u', '--diff-filter', dest='diff_file', default='', help='Unified diff file with changes which will be included into final report')
|
||||
parser.add_argument('-ub', '--diff-base-dir', dest='diff_base_dir', default='', help='Base directory for sources in unified diff file, usually repository dir')
|
||||
parser.add_argument('-ce', '--custom-exclusion-marker', dest='exclude_line_marker', nargs="+", metavar='', default=["LCOV_EXCL_LINE"], help='Filter: Add filter for lines that will be excluded from coverage (same behavior as "LCOV_EXCL_LINE")')
|
||||
|
||||
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('-c', '--compiler-directory', dest='cdirectory', default="", help='Base directory compiler was invoked from (default: . or read from gcov) \
|
||||
This needs to be set if invoking fastcov from somewhere other than the base compiler directory. No need to set it if gcc version > 9.1')
|
||||
|
||||
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). \
|
||||
@@ -672,17 +978,23 @@ def parseArgs():
|
||||
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('-o', '--output', dest='output', default="", help='Name of output file (default: coverage.json or coverage.info, depends on --lcov option)')
|
||||
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('-w', '--validate-sources', dest="validate_sources", action="store_true", help="Check if every source file exists")
|
||||
parser.add_argument('-p', '--dump-statistic', dest="dump_statistic", action="store_true", help="Dump total statistic at the end")
|
||||
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()
|
||||
parser.add_argument('-gps', '--gcov_prefix_strip', dest="gcov_prefix_strip", action="store", default=0, type=int, help="The number of initial directory names to strip off the absolute paths in the object file.")
|
||||
parser.add_argument('-gp', '--gcov_prefix', dest="gcov_prefix", action="store", default="", help="The prefix to add to the paths in the object file.")
|
||||
|
||||
args = parser.parse_args()
|
||||
if not args.output:
|
||||
args.output = 'coverage.info' if args.lcov else 'coverage.json'
|
||||
return args
|
||||
|
||||
def checkPythonVersion(version):
|
||||
@@ -717,6 +1029,12 @@ def main():
|
||||
# Setup logging
|
||||
setupLogging(args.quiet, args.verbose)
|
||||
|
||||
if args.gcov_prefix_strip > 0:
|
||||
os.environ["GCOV_PREFIX_STRIP"] = str(args.gcov_prefix_strip)
|
||||
|
||||
if len(args.gcov_prefix) > 0:
|
||||
os.environ["GCOV_PREFIX"] = args.gcov_prefix
|
||||
|
||||
# Get report from appropriate source
|
||||
if args.combine:
|
||||
fastcov_json = getCombineCoverage(args)
|
||||
@@ -727,9 +1045,16 @@ def main():
|
||||
|
||||
# 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)
|
||||
processExclusionMarkers(fastcov_json, args.jobs, args.exclude_branches_sw, args.include_branches_sw, args.exclude_line_marker, args.minimum_chunk, args.fallback_encodings, args.gcov_prefix, args.gcov_prefix_strip)
|
||||
logging.info("Scanned {} source files for exclusion markers".format(len(fastcov_json["sources"])))
|
||||
|
||||
if args.diff_file:
|
||||
logging.info("Filtering according to {} file".format(args.diff_file))
|
||||
DiffParser().filterByDiff(args.diff_file, args.diff_base_dir, fastcov_json, args.fallback_encodings)
|
||||
|
||||
if args.validate_sources:
|
||||
validateSources(fastcov_json, args.gcov_prefix, args.gcov_prefix_strip)
|
||||
|
||||
# Dump to desired file format
|
||||
dumpFile(fastcov_json, args)
|
||||
|
||||
|
||||
@@ -19,9 +19,12 @@ from argparse import ArgumentParser
|
||||
|
||||
|
||||
def interesting(s):
|
||||
if 'assert' in s: return 1
|
||||
if 'Assert' in s: return 1
|
||||
if 'Aborted' in s: return 1
|
||||
if 'assert' in s:
|
||||
return 1
|
||||
if 'Assert' in s:
|
||||
return 1
|
||||
if 'Aborted' in s:
|
||||
return 1
|
||||
if 'terminate' in s:
|
||||
if 'unterminated' in s:
|
||||
return 0
|
||||
@@ -41,8 +44,7 @@ def main():
|
||||
for infile in glob(args.dir + '/*'):
|
||||
# Input filenames are known not to contain spaces or other unusual
|
||||
# characters, therefore this works.
|
||||
status, output = getstatusoutput('../../bin/verilator_bin --cc ' +
|
||||
infile)
|
||||
status, output = getstatusoutput('../../bin/verilator_bin --cc ' + infile)
|
||||
if interesting(output):
|
||||
print(infile)
|
||||
print(status)
|
||||
|
||||
@@ -51,9 +51,11 @@ def write_file(filename, contents):
|
||||
|
||||
def parse_line(s):
|
||||
# str->maybe str
|
||||
if len(s) == 0: return None
|
||||
if len(s) == 0:
|
||||
return None
|
||||
part = skip_while(lambda x: x != '"', s)
|
||||
if len(part) == 0 or part[0] != '"': return None
|
||||
if len(part) == 0 or part[0] != '"':
|
||||
return None
|
||||
literal_part = take_while(lambda x: x != '"', part[1:])
|
||||
return ''.join(filter(lambda x: x != '\\', literal_part))
|
||||
|
||||
|
||||
+12
-19
@@ -31,7 +31,10 @@ def test():
|
||||
print("== stage 0")
|
||||
run("/bin/rm -rf " + blddir)
|
||||
run("/bin/mkdir -p " + blddir)
|
||||
run("cd " + blddir + " && " + srcdir + "/configure --prefix " + prefix)
|
||||
# Matches Ubuntu's e.g. /usr/share/pkgconfig/verilator.pc
|
||||
run("cd " + blddir + " && " + srcdir + "/configure --prefix " + prefix +
|
||||
" --exec-prefix " + prefix + " --datarootdir " + prefix + "/share" + " --includedir " +
|
||||
prefix + "/share/verilator/include")
|
||||
run("cd " + blddir + " && make -j " + str(calc_jobs()))
|
||||
|
||||
# Install it under the prefix
|
||||
@@ -41,8 +44,7 @@ def test():
|
||||
run("/bin/mkdir -p " + prefix)
|
||||
run("cd " + blddir + " && make install")
|
||||
run("test -e " + prefix + "/share/man/man1/verilator.1")
|
||||
run("test -e " + prefix +
|
||||
"/share/verilator/examples/make_tracing_c/Makefile")
|
||||
run("test -e " + prefix + "/share/verilator/examples/make_tracing_c/Makefile")
|
||||
run("test -e " + prefix + "/share/verilator/include/verilated.h")
|
||||
run("test -e " + prefix + "/bin/verilator")
|
||||
run("test -e " + prefix + "/bin/verilator_bin")
|
||||
@@ -58,10 +60,8 @@ def test():
|
||||
run("/bin/mkdir -p " + odir)
|
||||
path = prefix + "/bin" + ":" + prefix + "/share/bin"
|
||||
write_verilog(odir)
|
||||
run("cd " + odir + " && PATH=" + path +
|
||||
":$PATH verilator --cc top.v --exe sim_main.cpp")
|
||||
run("cd " + odir + "/obj_dir && PATH=" + path +
|
||||
":$PATH make -f Vtop.mk")
|
||||
run("cd " + odir + " && PATH=" + path + ":$PATH verilator --cc top.v --exe sim_main.cpp")
|
||||
run("cd " + odir + "/obj_dir && PATH=" + path + ":$PATH make -f Vtop.mk")
|
||||
run("cd " + odir + " && PATH=" + path + ":$PATH obj_dir/Vtop")
|
||||
|
||||
# run a test using exact path to binary
|
||||
@@ -72,8 +72,7 @@ def test():
|
||||
run("/bin/mkdir -p " + odir)
|
||||
write_verilog(odir)
|
||||
bin1 = prefix + "/bin"
|
||||
run("cd " + odir + " && " + bin1 +
|
||||
"/verilator --cc top.v --exe sim_main.cpp")
|
||||
run("cd " + odir + " && " + bin1 + "/verilator --cc top.v --exe sim_main.cpp")
|
||||
run("cd " + odir + "/obj_dir && make -f Vtop.mk")
|
||||
run("cd " + odir + "/obj_dir && ./Vtop")
|
||||
|
||||
@@ -88,8 +87,7 @@ def write_verilog(odir):
|
||||
|
||||
def cleanenv():
|
||||
for var in os.environ:
|
||||
if var in ('VERILATOR_ROOT', 'VERILATOR_INCLUDE',
|
||||
'VERILATOR_NO_OPT_BUILD'):
|
||||
if var in ('VERILATOR_ROOT', 'VERILATOR_INCLUDE', 'VERILATOR_NO_OPT_BUILD'):
|
||||
print("unset %s # Was '%s'" % (var, os.environ[var]))
|
||||
del os.environ[var]
|
||||
|
||||
@@ -113,21 +111,16 @@ def run(command):
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description=
|
||||
"""install_test performs several make-and-install iterations to verify the
|
||||
description="""install_test performs several make-and-install iterations to verify the
|
||||
Verilator kit. It isn't part of the normal "make test" due to the number
|
||||
of builds required.""",
|
||||
epilog=
|
||||
"""Copyright 2009-2024 by Wilson Snyder. This program is free software; you
|
||||
epilog="""Copyright 2009-2024 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""")
|
||||
parser.add_argument('--debug',
|
||||
action='store_const',
|
||||
const=9,
|
||||
help='enable debug')
|
||||
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||
parser.add_argument('--stage',
|
||||
type=int,
|
||||
default=0,
|
||||
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
import re
|
||||
import sys
|
||||
|
||||
SUPPRESSES = [
|
||||
"**********",
|
||||
"E0602: Undefined variable 'test' (undefined-variable)",
|
||||
"E0602: Undefined variable 're' (undefined-variable)",
|
||||
"E0602: Undefined variable 'os' (undefined-variable)",
|
||||
"E0602: Undefined variable 'glob' (undefined-variable)",
|
||||
"W0611: Unused import vltest_bootstrap (unused-import)",
|
||||
]
|
||||
|
||||
######################################################################
|
||||
|
||||
def process():
|
||||
anymsg = False
|
||||
for line in sys.stdin:
|
||||
line = line.rstrip();
|
||||
show = True
|
||||
for msg in SUPPRESSES:
|
||||
if msg in line:
|
||||
show = False
|
||||
continue
|
||||
if show:
|
||||
print(line)
|
||||
anymsg = True
|
||||
|
||||
if anymsg:
|
||||
sys.exit("%Error: See messages above")
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
description="""lint_py_test_filter is used to filter
|
||||
pylint output for expected errors in Verilator test_regress/*.py tests.""",
|
||||
epilog="""Copyright 2024-2024 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""")
|
||||
|
||||
parser.add_argument('--debug', action='store_true', help='enable debug')
|
||||
|
||||
Args = parser.parse_args()
|
||||
process()
|
||||
|
||||
######################################################################
|
||||
# Local Variables:
|
||||
# compile-command: "cd .. ; make lint-py-pylint-tests"
|
||||
# End:
|
||||
Executable
+119
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0114,C0116,C0209,R0912,R0915
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import re
|
||||
#from pprint import pprint,pformat
|
||||
|
||||
#######################################################################
|
||||
|
||||
|
||||
def message_section(msg):
|
||||
"""Return sorting-section number for given commit message"""
|
||||
if re.match(r'^Support', msg):
|
||||
return 10
|
||||
if re.match(r'^Add', msg):
|
||||
return 20
|
||||
if re.match(r'^Improve', msg):
|
||||
return 30
|
||||
if re.match(r'^Fix', msg):
|
||||
return 40
|
||||
if re.match(r'^(Internals|CI|Tests)', msg):
|
||||
return -1
|
||||
return 0
|
||||
|
||||
|
||||
def process():
|
||||
cmd = "git log"
|
||||
|
||||
msgs = {}
|
||||
with os.popen(cmd) as fh:
|
||||
author = ""
|
||||
lineno = 0
|
||||
for line in fh:
|
||||
lineno += 1
|
||||
line = line.rstrip()
|
||||
if re.match(r'^Date', line):
|
||||
continue
|
||||
if re.match(r'^commit', line):
|
||||
continue
|
||||
if re.search(r'Commentary: Changes update', line):
|
||||
break
|
||||
|
||||
am = re.match(r'^Author: (.*) <(.*)>', line)
|
||||
dm = re.match(r'^ +(.*)', line)
|
||||
|
||||
if am:
|
||||
email = am.group(2)
|
||||
author = am.group(1)
|
||||
if re.search(r'antmicro', email):
|
||||
author += ", Antmicro Ltd."
|
||||
if re.search(r'github action', author):
|
||||
author = ""
|
||||
continue
|
||||
|
||||
elif author != "" and dm:
|
||||
msg = dm.group(1)
|
||||
if not re.search(r'\.$', msg):
|
||||
msg += '.'
|
||||
msg += ' [' + author + ']'
|
||||
|
||||
mid = re.search(r'\(#([0-9][0-9][0-9][0-9]+)', line)
|
||||
if mid:
|
||||
bug_id = mid.group(1)
|
||||
else:
|
||||
bug_id = " %d" % lineno
|
||||
|
||||
section = message_section(msg)
|
||||
if section >= 0:
|
||||
key = "%06s_%06s_%06d" % (section, bug_id, lineno)
|
||||
msgs[key] = '* ' + msg
|
||||
# print("i [%s] %s" % (key, msg))
|
||||
|
||||
author = ""
|
||||
|
||||
if not msgs:
|
||||
print("No Changes need to be inserted.")
|
||||
return
|
||||
|
||||
print()
|
||||
print("Insertion-sort the following lines into 'Changes' file:")
|
||||
print()
|
||||
|
||||
dedup = {}
|
||||
for key in sorted(msgs.keys()):
|
||||
if msgs[key] not in dedup:
|
||||
dedup[msgs[key]] = True
|
||||
print(msgs[key])
|
||||
|
||||
print()
|
||||
print("You may now want to clean up spelling, and commit:")
|
||||
print(" (cd docs ; make spelling)")
|
||||
print(" git ci -am 'Commentary: Changes update'")
|
||||
print()
|
||||
|
||||
|
||||
#######################################################################
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
allow_abbrev=False,
|
||||
prog="log_changes",
|
||||
description="Create example entries for 'Changes' from parsing 'git log'",
|
||||
epilog="""Copyright 2019-2024 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""")
|
||||
|
||||
parser.add_argument('--debug', action='store_true', help='enable debug')
|
||||
Args = parser.parse_args()
|
||||
|
||||
process()
|
||||
|
||||
######################################################################
|
||||
# Local Variables:
|
||||
# compile-command: "cd .. ; nodist/log_changes"
|
||||
# End:
|
||||
+9
-7
@@ -47,9 +47,12 @@ class AstseeCmd(gdb.Command):
|
||||
|
||||
def _null_check(self, old, new):
|
||||
err = ""
|
||||
if old == "<nullptr>\n": err += "old == <nullptr>\n"
|
||||
if new == "<nullptr>\n": err += "new == <nullptr>"
|
||||
if err: raise gdb.GdbError(err.strip("\n"))
|
||||
if old == "<nullptr>\n":
|
||||
err += "old == <nullptr>\n"
|
||||
if new == "<nullptr>\n":
|
||||
err += "new == <nullptr>"
|
||||
if err:
|
||||
raise gdb.GdbError(err.strip("\n"))
|
||||
|
||||
def invoke(self, arg_str, from_tty):
|
||||
from astsee import verilator_cli as astsee # pylint: disable=import-error,import-outside-toplevel
|
||||
@@ -58,8 +61,8 @@ class AstseeCmd(gdb.Command):
|
||||
# We hack `astsee_verilator`'s arg parser to find arguments with nodes
|
||||
# After finding them, we replace them with proper files
|
||||
astsee_args = astsee.parser.parse_args(gdb.string_to_argv(arg_str))
|
||||
with _vltgdb_tmpfile() as oldfile, _vltgdb_tmpfile(
|
||||
) as newfile, _vltgdb_tmpfile() as metafile:
|
||||
with _vltgdb_tmpfile() as oldfile, _vltgdb_tmpfile() as newfile, _vltgdb_tmpfile(
|
||||
) as metafile:
|
||||
if astsee_args.file:
|
||||
_vltgdb_fwrite(oldfile, _vltgdb_get_dump(astsee_args.file))
|
||||
astsee_args.file = oldfile.name
|
||||
@@ -68,8 +71,7 @@ class AstseeCmd(gdb.Command):
|
||||
astsee_args.newfile = newfile.name
|
||||
if astsee_args.meta is None:
|
||||
# pass
|
||||
gdb.execute(
|
||||
f'call AstNode::dumpJsonMetaFileGdb("{metafile.name}")')
|
||||
gdb.execute(f'call AstNode::dumpJsonMetaFileGdb("{metafile.name}")')
|
||||
astsee_args.meta = metafile.name
|
||||
try:
|
||||
astsee.main(astsee_args)
|
||||
|
||||
+124
-74
@@ -14,14 +14,23 @@
|
||||
|
||||
#
|
||||
# Utilities
|
||||
macro (addBuildType sourceConfig newConfig)
|
||||
macro(addBuildType sourceConfig newConfig)
|
||||
get_cmake_property(variableNames VARIABLES)
|
||||
foreach (variableName ${variableNames})
|
||||
if (variableName MATCHES "^CMAKE_.*_${sourceConfig}(|_.*)$")
|
||||
string(REPLACE _${sourceConfig} _${newConfig} newVariableName ${variableName})
|
||||
foreach(variableName ${variableNames})
|
||||
if(variableName MATCHES "^CMAKE_.*_${sourceConfig}(|_.*)$")
|
||||
string(
|
||||
REPLACE
|
||||
_${sourceConfig}
|
||||
_${newConfig}
|
||||
newVariableName
|
||||
${variableName}
|
||||
)
|
||||
set(${newVariableName} ${${variableName}})
|
||||
mark_as_advanced(${newVariableName})
|
||||
message(DEBUG " Propagating ${variableName} to ${newVariableName} = ${${newVariableName}}")
|
||||
message(
|
||||
DEBUG
|
||||
" Propagating ${variableName} to ${newVariableName} = ${${newVariableName}}"
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
endmacro()
|
||||
@@ -142,6 +151,7 @@ set(HEADERS
|
||||
V3Randomize.h
|
||||
V3Reloop.h
|
||||
V3Rtti.h
|
||||
V3Sampled.h
|
||||
V3Sched.h
|
||||
V3Scope.h
|
||||
V3Scoreboard.h
|
||||
@@ -162,7 +172,6 @@ set(HEADERS
|
||||
V3Table.h
|
||||
V3Task.h
|
||||
V3ThreadPool.h
|
||||
V3ThreadSafety.h
|
||||
V3Timing.h
|
||||
V3Trace.h
|
||||
V3TraceDecl.h
|
||||
@@ -288,6 +297,7 @@ set(COMMON_SOURCES
|
||||
V3ProtectLib.cpp
|
||||
V3Randomize.cpp
|
||||
V3Reloop.cpp
|
||||
V3Sampled.cpp
|
||||
V3Sched.cpp
|
||||
V3SchedAcyclic.cpp
|
||||
V3SchedPartition.cpp
|
||||
@@ -326,15 +336,11 @@ set(COMMON_SOURCES
|
||||
V3PreProc.cpp
|
||||
)
|
||||
|
||||
SET(COVERAGE_SOURCES
|
||||
VlcMain.cpp
|
||||
)
|
||||
set(COVERAGE_SOURCES VlcMain.cpp)
|
||||
|
||||
# Note about tests:
|
||||
# VlcMain.cpp #includes the following files:
|
||||
# V3Error.cpp, V3String.cpp, V3Os.cpp and VlcTop.cpp
|
||||
# V3Number_test.cpp #includes the following files:
|
||||
# V3FileLine.cpp
|
||||
|
||||
#
|
||||
# Generated sources and headers for the verilator binary
|
||||
@@ -353,34 +359,49 @@ configure_file(config_package.h.in config_package.h @ONLY)
|
||||
add_custom_command(
|
||||
OUTPUT V3Ast__gen_forward_class_decls.h V3Dfg__gen_forward_class_decls.h
|
||||
DEPENDS ./V3Ast.h ${ASTGEN}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h --classes
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef
|
||||
V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h
|
||||
--classes
|
||||
)
|
||||
list(
|
||||
APPEND
|
||||
GENERATED_FILES
|
||||
V3Ast__gen_forward_class_decls.h
|
||||
V3Dfg__gen_forward_class_decls.h
|
||||
)
|
||||
list(APPEND GENERATED_FILES V3Ast__gen_forward_class_decls.h V3Dfg__gen_forward_class_decls.h)
|
||||
# Output used directly by the `verilator` target
|
||||
|
||||
set(verilog_y "${srcdir}/verilog.y" )
|
||||
set(BISON_V3ParseBison_OUTPUT_HEADER "${CMAKE_CURRENT_BINARY_DIR}/V3ParseBison.h")
|
||||
set(BISON_V3ParseBison_OUTPUT_SOURCE "${CMAKE_CURRENT_BINARY_DIR}/V3ParseBison.c")
|
||||
set(verilog_y "${srcdir}/verilog.y")
|
||||
set(BISON_V3ParseBison_OUTPUT_HEADER
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/V3ParseBison.h"
|
||||
)
|
||||
set(BISON_V3ParseBison_OUTPUT_SOURCE
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/V3ParseBison.c"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT V3ParseBison.c V3ParseBison.h
|
||||
MAIN_DEPENDENCY ./verilog.y
|
||||
DEPENDS ${BISONPRE}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${BISONPRE} --yacc "${BISON_EXECUTABLE}" -d -v
|
||||
-o "${BISON_V3ParseBison_OUTPUT_SOURCE}" "${verilog_y}"
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${BISONPRE} --yacc "${BISON_EXECUTABLE}" -d -v -o
|
||||
"${BISON_V3ParseBison_OUTPUT_SOURCE}" "${verilog_y}"
|
||||
)
|
||||
list(APPEND GENERATED_FILES V3ParseBison.c V3ParseBison.h)
|
||||
# Output used directly by the `verilator` target
|
||||
|
||||
set(verilog_l "${srcdir}/verilog.l")
|
||||
set(FLEX_V3Lexer_pregen_OUTPUTS "${CMAKE_CURRENT_BINARY_DIR}/V3Lexer_pregen.yy.cpp")
|
||||
set(FLEX_V3Lexer_pregen_OUTPUTS
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/V3Lexer_pregen.yy.cpp"
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT V3Lexer_pregen.yy.cpp
|
||||
MAIN_DEPENDENCY ./verilog.l
|
||||
DEPENDS ${BISON_V3ParseBison_OUTPUT_HEADER} ${HEADERS}
|
||||
COMMAND ${FLEX_EXECUTABLE} ARGS
|
||||
${LFLAGS} -o "${FLEX_V3Lexer_pregen_OUTPUTS}" "${verilog_l}"
|
||||
COMMAND ${FLEX_EXECUTABLE}
|
||||
ARGS ${LFLAGS} -o "${FLEX_V3Lexer_pregen_OUTPUTS}" "${verilog_l}"
|
||||
)
|
||||
# Output used by another command
|
||||
|
||||
@@ -389,19 +410,26 @@ add_custom_command(
|
||||
OUTPUT V3Lexer.yy.cpp
|
||||
MAIN_DEPENDENCY ${FLEX_V3Lexer_pregen_OUTPUTS}
|
||||
DEPENDS ${FLEXFIX}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${FLEXFIX} V3Lexer < "$<SHELL_PATH:${FLEX_V3Lexer_pregen_OUTPUTS}>" > "$<SHELL_PATH:${FLEX_V3Lexer_OUTPUTS}>"
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${FLEXFIX} V3Lexer < "$<SHELL_PATH:${FLEX_V3Lexer_pregen_OUTPUTS}>" >
|
||||
"$<SHELL_PATH:${FLEX_V3Lexer_OUTPUTS}>"
|
||||
)
|
||||
add_custom_target(
|
||||
V3Lexer_yy_cpp${CMAKE_BUILD_TYPE}
|
||||
DEPENDS ${FLEX_V3Lexer_OUTPUTS}
|
||||
)
|
||||
add_custom_target(V3Lexer_yy_cpp${CMAKE_BUILD_TYPE} DEPENDS ${FLEX_V3Lexer_OUTPUTS})
|
||||
# Output included by another source file
|
||||
|
||||
set(FLEX_V3PreLex_pregen_OUTPUTS ${CMAKE_CURRENT_BINARY_DIR}/V3PreLex_pregen.yy.cpp)
|
||||
set(FLEX_V3PreLex_pregen_OUTPUTS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/V3PreLex_pregen.yy.cpp
|
||||
)
|
||||
add_custom_command(
|
||||
OUTPUT V3PreLex_pregen.yy.cpp
|
||||
MAIN_DEPENDENCY ./V3PreLex.l
|
||||
DEPENDS ${HEADERS}
|
||||
COMMAND ${FLEX_EXECUTABLE} ARGS
|
||||
${LFLAGS} -o "${FLEX_V3PreLex_pregen_OUTPUTS}" "${srcdir}/V3PreLex.l"
|
||||
COMMAND ${FLEX_EXECUTABLE}
|
||||
ARGS ${LFLAGS} -o "${FLEX_V3PreLex_pregen_OUTPUTS}" "${srcdir}/V3PreLex.l"
|
||||
)
|
||||
# Output used by another command
|
||||
|
||||
@@ -410,37 +438,45 @@ add_custom_command(
|
||||
OUTPUT V3PreLex.yy.cpp
|
||||
MAIN_DEPENDENCY ${FLEX_V3PreLex_pregen_OUTPUTS}
|
||||
DEPENDS ${FLEXFIX}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${FLEXFIX} V3PreLex < "$<SHELL_PATH:${FLEX_V3PreLex_pregen_OUTPUTS}>" > "$<SHELL_PATH:${FLEX_V3PreLex_OUTPUTS}>"
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${FLEXFIX} V3PreLex < "$<SHELL_PATH:${FLEX_V3PreLex_pregen_OUTPUTS}>" >
|
||||
"$<SHELL_PATH:${FLEX_V3PreLex_OUTPUTS}>"
|
||||
)
|
||||
add_custom_target(
|
||||
V3PreLex_yy_cpp${CMAKE_BUILD_TYPE}
|
||||
DEPENDS ${FLEX_V3PreLex_OUTPUTS}
|
||||
)
|
||||
add_custom_target(V3PreLex_yy_cpp${CMAKE_BUILD_TYPE} DEPENDS ${FLEX_V3PreLex_OUTPUTS})
|
||||
# Output included by another source file
|
||||
|
||||
set(gitHead ${srcdir}/../.git/logs/HEAD)
|
||||
if (NOT EXISTS ${githead})
|
||||
if(NOT EXISTS ${githead})
|
||||
set(gitHead "")
|
||||
endif()
|
||||
add_custom_command(
|
||||
OUTPUT config_rev.h
|
||||
MAIN_DEPENDENCY ${gitHead}
|
||||
DEPENDS ${CONFIG_REV}
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${CONFIG_REV} "${srcdir}" > "$<SHELL_PATH:${CMAKE_CURRENT_BINARY_DIR}/config_rev.h>"
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${CONFIG_REV} "${srcdir}" >
|
||||
"$<SHELL_PATH:${CMAKE_CURRENT_BINARY_DIR}/config_rev.h>"
|
||||
)
|
||||
list(APPEND GENERATED_FILES config_rev.h)
|
||||
# Output used directly by the `verilator` target
|
||||
|
||||
set(ASTGENERATED_NAMES
|
||||
V3Const
|
||||
)
|
||||
set(ASTGENERATED_NAMES V3Const)
|
||||
|
||||
foreach(astgen_name ${ASTGENERATED_NAMES})
|
||||
add_custom_command(
|
||||
OUTPUT ${astgen_name}__gen.cpp
|
||||
MAIN_DEPENDENCY ${astgen_name}.cpp
|
||||
DEPENDS ${ASTGEN} V3Ast.h
|
||||
COMMAND ${PYTHON3} ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h ${astgen_name}.cpp
|
||||
COMMAND ${PYTHON3}
|
||||
ARGS
|
||||
${ASTGEN} -I "${srcdir}" --astdef V3AstNodeDType.h --astdef
|
||||
V3AstNodeExpr.h --astdef V3AstNodeOther.h --dfgdef V3DfgVertices.h
|
||||
${astgen_name}.cpp
|
||||
)
|
||||
list(APPEND GENERATED_FILES ${astgen_name}__gen.cpp)
|
||||
endforeach()
|
||||
@@ -448,7 +484,7 @@ endforeach()
|
||||
#
|
||||
# Set up the Coverage build type
|
||||
|
||||
addBuildType(DEBUG COVERAGE)
|
||||
addbuildtype(DEBUG COVERAGE)
|
||||
|
||||
# This regenerates include/verilated_cov_key.h in the source tree.
|
||||
# It is a custom_target, not custom_command, because vlcovgen.d is
|
||||
@@ -457,8 +493,7 @@ add_custom_target(
|
||||
vlcovgen.d${CMAKE_BUILD_TYPE}
|
||||
DEPENDS ../include/verilated_cov_key.h ${VLCOVGEN}
|
||||
COMMENT "Updating include/verilated_cov_key.h"
|
||||
COMMAND ${PYTHON3}
|
||||
${VLCOVGEN} --srcdir ${srcdir}
|
||||
COMMAND ${PYTHON3} ${VLCOVGEN} --srcdir ${srcdir}
|
||||
)
|
||||
|
||||
#
|
||||
@@ -466,66 +501,81 @@ add_custom_target(
|
||||
|
||||
set(verilator verilator${CMAKE_BUILD_TYPE})
|
||||
|
||||
add_executable(${verilator}
|
||||
add_executable(
|
||||
${verilator}
|
||||
$<$<NOT:$<CONFIG:COVERAGE>>:${COMMON_SOURCES}>
|
||||
$<$<NOT:$<CONFIG:COVERAGE>>:${GENERATED_FILES}>
|
||||
$<$<CONFIG:COVERAGE>:${COVERAGE_SOURCES} config_rev.h>
|
||||
$<$<CONFIG:COVERAGE>:${COVERAGE_SOURCES}
|
||||
config_rev.h>
|
||||
)
|
||||
|
||||
set_target_properties(${verilator} PROPERTIES
|
||||
OUTPUT_NAME_RELEASE verilator_bin
|
||||
OUTPUT_NAME_DEBUG verilator_bin_dbg
|
||||
OUTPUT_NAME_COVERAGE verilator_coverage_bin_dbg
|
||||
#UNITY_BUILD $<IF:$<CONFIG:DEBUG>,FALSE,${CMAKE_UNITY_BUILD}>
|
||||
MSVC_RUNTIME_LIBRARY MultiThreaded$<IF:$<CONFIG:Release>,,DebugDLL>
|
||||
#JOB_POOL_LINK one_job # Linking takes lots of resources
|
||||
INTERPROCEDURAL_OPTIMIZATION_RELEASE $<IF:MINGW,FALSE,TRUE>
|
||||
INCLUDE_DIRECTORIES ${FLEX_INCLUDE_DIR}
|
||||
set_target_properties(
|
||||
${verilator}
|
||||
PROPERTIES
|
||||
OUTPUT_NAME_RELEASE verilator_bin
|
||||
OUTPUT_NAME_DEBUG verilator_bin_dbg
|
||||
OUTPUT_NAME_COVERAGE verilator_coverage_bin_dbg
|
||||
#UNITY_BUILD $<IF:$<CONFIG:DEBUG>,FALSE,${CMAKE_UNITY_BUILD}>
|
||||
MSVC_RUNTIME_LIBRARY MultiThreaded$<IF:$<CONFIG:Release>,,DebugDLL>
|
||||
#JOB_POOL_LINK one_job # Linking takes lots of resources
|
||||
INTERPROCEDURAL_OPTIMIZATION_RELEASE $<IF:MINGW,FALSE,TRUE>
|
||||
INCLUDE_DIRECTORIES ${FLEX_INCLUDE_DIR}
|
||||
)
|
||||
|
||||
add_dependencies(${verilator}
|
||||
add_dependencies(
|
||||
${verilator}
|
||||
V3Lexer_yy_cpp${CMAKE_BUILD_TYPE}
|
||||
V3PreLex_yy_cpp${CMAKE_BUILD_TYPE}
|
||||
)
|
||||
|
||||
target_link_libraries(${verilator} PRIVATE Threads::Threads)
|
||||
|
||||
# verilated_cov_key.h is only regenerated in a single-configuration environment.
|
||||
# This limitation can be lifted when `add_dependencies` will support generator
|
||||
# expressions. See https://gitlab.kitware.com/cmake/cmake/issues/19467
|
||||
if (CMAKE_BUILD_TYPE STREQUAL Coverage)
|
||||
if(CMAKE_BUILD_TYPE STREQUAL Coverage)
|
||||
add_dependencies(${verilator} vlcovgen.d${CMAKE_BUILD_TYPE})
|
||||
endif()
|
||||
|
||||
if (NOT MSVC)
|
||||
if(NOT MSVC)
|
||||
target_compile_features(${verilator} PRIVATE cxx_std_11)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${verilator} PRIVATE
|
||||
YYDEBUG # Required to get nice error messages
|
||||
$<$<CONFIG:DEBUG>:VL_DEBUG>
|
||||
$<$<CONFIG:DEBUG>:_GLIBCXX_DEBUG>
|
||||
)
|
||||
|
||||
target_include_directories(${verilator}
|
||||
target_compile_definitions(
|
||||
${verilator}
|
||||
PRIVATE
|
||||
../include
|
||||
${WIN_FLEX_BISON}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
YYDEBUG # Required to get nice error messages
|
||||
$<$<CONFIG:DEBUG>:VL_DEBUG>
|
||||
$<$<CONFIG:DEBUG>:_GLIBCXX_DEBUG>
|
||||
)
|
||||
|
||||
if (WIN32)
|
||||
target_include_directories(
|
||||
${verilator}
|
||||
PRIVATE
|
||||
../include
|
||||
${WIN_FLEX_BISON}
|
||||
${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_CURRENT_BINARY_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
|
||||
if(WIN32)
|
||||
if(MINGW)
|
||||
target_compile_options(${verilator} PRIVATE -Wa,-mbig-obj)
|
||||
target_link_options(${verilator} PRIVATE -Wl,--stack,10000000 -mconsole -lcomctl32 -DWIN_32_LEAN_AND_MEAN)
|
||||
target_link_options(
|
||||
${verilator}
|
||||
PRIVATE
|
||||
-Wl,--stack,10000000
|
||||
-mconsole
|
||||
-lcomctl32
|
||||
-DWIN_32_LEAN_AND_MEAN
|
||||
)
|
||||
else()
|
||||
target_compile_options(${verilator} PRIVATE /bigobj)
|
||||
target_link_options(${verilator} PRIVATE /STACK:10000000)
|
||||
endif()
|
||||
|
||||
target_compile_definitions(${verilator} PRIVATE
|
||||
YY_NO_UNISTD_H
|
||||
)
|
||||
target_compile_definitions(${verilator} PRIVATE YY_NO_UNISTD_H)
|
||||
target_include_directories(${verilator} PRIVATE ../platform/win32)
|
||||
target_link_libraries(${verilator} PRIVATE bcrypt psapi)
|
||||
endif()
|
||||
|
||||
+4
-6
@@ -49,7 +49,7 @@ prefix = @prefix@
|
||||
# Directory in which to install data across multiple architectures
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
# Directory in which to install package specific files
|
||||
# Directory in which to install package-specific files
|
||||
# Generally ${prefix}/share/verilator
|
||||
pkgdatadir = @pkgdatadir@
|
||||
|
||||
@@ -210,6 +210,7 @@ RAW_OBJS_PCH_ASTMT = \
|
||||
V3Options.o \
|
||||
V3Stats.o \
|
||||
V3StatsReport.o \
|
||||
V3VariableOrder.o \
|
||||
|
||||
RAW_OBJS_PCH_ASTNOMT = \
|
||||
V3Active.o \
|
||||
@@ -284,6 +285,7 @@ RAW_OBJS_PCH_ASTNOMT = \
|
||||
V3ProtectLib.o \
|
||||
V3Randomize.o \
|
||||
V3Reloop.o \
|
||||
V3Sampled.o \
|
||||
V3Sched.o \
|
||||
V3SchedAcyclic.o \
|
||||
V3SchedPartition.o \
|
||||
@@ -308,7 +310,6 @@ RAW_OBJS_PCH_ASTNOMT = \
|
||||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3VariableOrder.o \
|
||||
V3Width.o \
|
||||
V3WidthCommit.o \
|
||||
V3WidthSel.o \
|
||||
@@ -354,9 +355,6 @@ $(TGT): $(PREDEP_H) $(OBJS)
|
||||
@echo " Linking $@..."
|
||||
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
|
||||
|
||||
V3Number_test: V3Number_test.o
|
||||
${LINK} ${LDFLAGS} -o $@ $^ ${LIBS}
|
||||
|
||||
#### Modules
|
||||
|
||||
%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS)
|
||||
@@ -365,7 +363,7 @@ V3Number_test: V3Number_test.o
|
||||
.SECONDARY:
|
||||
|
||||
%.gch: %
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH} $< -o $@
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} ${CFG_CXXFLAGS_PCH} -c $< -o $@
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
%.o: %.c
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user