mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +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 | ||
|
|
cd693ce02b | ||
|
|
2641bc98aa | ||
|
|
ad2862ce3f | ||
|
|
4695967185 | ||
|
|
f96e99542c | ||
|
|
7de193c2e9 | ||
|
|
442c9bc316 | ||
|
|
3203019408 | ||
|
|
bc853e260b | ||
|
|
d6e5703298 | ||
|
|
a9e50327fd | ||
|
|
6f0a36318e | ||
|
|
221fecad0b | ||
|
|
fd1e4d9e45 | ||
|
|
920ed5ca3d | ||
|
|
2537431273 | ||
|
|
13114f2efe | ||
|
|
e9f59e44a5 | ||
|
|
d4c3e35f97 | ||
|
|
02dd33b60e | ||
|
|
2bc883f3b3 | ||
|
|
29db25b70e | ||
|
|
d6bc0c712a | ||
|
|
962efa3691 | ||
|
|
4babba16d6 | ||
|
|
5363d89870 | ||
|
|
44acb08ea9 | ||
|
|
6584b4d426 | ||
|
|
9ff06c1664 | ||
|
|
1537c9badc | ||
|
|
708f875b31 | ||
|
|
0d3cb86a44 | ||
|
|
5c2b9d55b2 | ||
|
|
1dbf1be3e6 | ||
|
|
3f886f7c61 | ||
|
|
7c9fa8647c | ||
|
|
dbf68a99e8 | ||
|
|
53c2e416f4 | ||
|
|
e834b5be2d | ||
|
|
bd7689f59a | ||
|
|
3496eb80a5 | ||
|
|
839c3bf444 | ||
|
|
d4b3583307 | ||
|
|
ee130cb20d | ||
|
|
552a146f9c | ||
|
|
913679f261 | ||
|
|
d9078df650 | ||
|
|
f84592af49 | ||
|
|
5f85c89425 | ||
|
|
94f789b677 | ||
|
|
739be2f782 | ||
|
|
25b9a16bc7 | ||
|
|
9a8e68928d | ||
|
|
19cccd170e | ||
|
|
d99c8f5d44 | ||
|
|
cf111d2e1f | ||
|
|
45eb5b8a5c | ||
|
|
ce5cad17a8 | ||
|
|
ed01befc25 | ||
|
|
69a2bfee68 | ||
|
|
1cc37ad6ce | ||
|
|
2a9f29912c | ||
|
|
298e0f24d1 | ||
|
|
80b08b71aa | ||
|
|
64ba569f0d | ||
|
|
3cb4033c97 | ||
|
|
6509bac59e | ||
|
|
ec45a77d93 | ||
|
|
8044833c74 | ||
|
|
3f89bdcfac | ||
|
|
c99364b81a | ||
|
|
d841a791e6 | ||
|
|
b5b937e2f2 | ||
|
|
4a41f69293 | ||
|
|
8fd038f88e | ||
|
|
4982f63da2 | ||
|
|
71bc60fb91 | ||
|
|
0da7ecf753 | ||
|
|
25ca1af8b3 | ||
|
|
5d54fa8e6f | ||
|
|
e8c5b9faad | ||
|
|
8e0301c287 | ||
|
|
3f625fc359 | ||
|
|
72b96d5069 | ||
|
|
d1b45b8d32 | ||
|
|
5601056ed0 | ||
|
|
8ed269c77f | ||
|
|
27b7e70218 | ||
|
|
97680656d3 | ||
|
|
4202ec2ab2 | ||
|
|
4f3a816fb0 | ||
|
|
25fd8ef5c0 | ||
|
|
a9664b8d16 | ||
|
|
26a5729514 | ||
|
|
5b839699ac | ||
|
|
1315aa31ed | ||
|
|
5d8da6b4ac | ||
|
|
aac2563a07 | ||
|
|
8e44487354 | ||
|
|
1012c054e6 | ||
|
|
a8b5738b44 | ||
|
|
72845167e6 | ||
|
|
7ca2d6470a | ||
|
|
33e999e01a |
+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: ''
|
WarningsAsErrors: ''
|
||||||
HeaderFilterRegex: ''
|
HeaderFilterRegex: ''
|
||||||
FormatStyle: none
|
FormatStyle: none
|
||||||
|
|||||||
+4
-4
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
exclude_paths:
|
exclude_paths:
|
||||||
- '.github/**'
|
- ".github/**"
|
||||||
- 'ci/build_verilator.sh'
|
- "ci/build_verilator.sh"
|
||||||
- 'include/vltstd/**'
|
- "include/vltstd/**"
|
||||||
- 'nodist/fastcov.py'
|
- "nodist/fastcov.py"
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Verilator Build Environment",
|
"name": "Verilator Build Environment",
|
||||||
|
|
||||||
"build": {
|
"build": {
|
||||||
"dockerfile": "../ci/docker/buildenv/Dockerfile"
|
"dockerfile": "../ci/docker/buildenv/Dockerfile"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -18,3 +18,5 @@ What 'verilator --version' are you using? Did you try it with the git master ve
|
|||||||
What OS and distribution are you using?
|
What OS and distribution are you using?
|
||||||
|
|
||||||
May we assist you in trying to fix this in Verilator yourself?
|
May we assist you in trying to fix this in Verilator yourself?
|
||||||
|
|
||||||
|
(Please avoid attaching screenshots that show text - you can convert images to text using e.g. https://ocr.space)
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ Thanks for taking the time to report this.
|
|||||||
|
|
||||||
What would you like added/supported?
|
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.)
|
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?
|
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?
|
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
|
# DESCRIPTION: Github actions config
|
||||||
# This name is key to badges in README.rst, so we use the name build
|
# 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
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
@@ -9,7 +10,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0' # weekly
|
- cron: '0 0 * * 0' # weekly
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: linux
|
CI_OS_NAME: linux
|
||||||
@@ -35,14 +36,14 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-22.04, ubuntu-20.04]
|
os: [ubuntu-24.04, ubuntu-22.04, ubuntu-20.04]
|
||||||
compiler:
|
compiler:
|
||||||
- { cc: clang, cxx: clang++ }
|
- {cc: clang, cxx: clang++}
|
||||||
- { cc: gcc, cxx: g++ }
|
- {cc: gcc, cxx: g++}
|
||||||
include:
|
include:
|
||||||
# Build GCC 10 on ubuntu-20.04
|
# Build GCC 10 on ubuntu-20.04
|
||||||
- os: 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 }}
|
runs-on: ${{ matrix.os }}
|
||||||
name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }}
|
name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }}
|
||||||
env:
|
env:
|
||||||
@@ -51,41 +52,40 @@ jobs:
|
|||||||
CC: ${{ matrix.compiler.cc }}
|
CC: ${{ matrix.compiler.cc }}
|
||||||
CXX: ${{ matrix.compiler.cxx }}
|
CXX: ${{ matrix.compiler.cxx }}
|
||||||
CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}
|
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
|
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
|
|
||||||
- name: Cache $CCACHE_DIR
|
- name: Cache $CCACHE_DIR
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
env:
|
env:
|
||||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||||
with:
|
with:
|
||||||
path: ${{ env.CCACHE_DIR }}
|
path: ${{ env.CCACHE_DIR }}
|
||||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ env.CACHE_KEY }}-
|
${{ env.CACHE_KEY }}-
|
||||||
|
|
||||||
- name: Install packages for build
|
- name: Install packages for build
|
||||||
run: ./ci/ci-install.bash
|
run: ./ci/ci-install.bash
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./ci/ci-script.bash
|
run: ./ci/ci-script.bash
|
||||||
|
|
||||||
- name: Tar up repository
|
- name: Tar up repository
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
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: Upload tar archive
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||||
|
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||||
|
|
||||||
test:
|
test:
|
||||||
needs: build
|
needs: build
|
||||||
@@ -94,25 +94,25 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
os: [ubuntu-22.04, ubuntu-20.04]
|
os: [ubuntu-22.04, ubuntu-20.04]
|
||||||
compiler:
|
compiler:
|
||||||
- { cc: clang, cxx: clang++ }
|
- {cc: clang, cxx: clang++}
|
||||||
- { cc: gcc, cxx: g++ }
|
- {cc: gcc, cxx: g++}
|
||||||
reloc: [0]
|
reloc: [0]
|
||||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1]
|
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, dist-vlt-3, vltmt-0, vltmt-1]
|
||||||
include:
|
include:
|
||||||
# Test with GCC 10 on ubuntu-20.04
|
# Test with GCC 10 on ubuntu-20.04, also test relocation
|
||||||
- {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}, reloc: 1, 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}, reloc: 1, 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}, reloc: 1, 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}, reloc: 1, 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}, reloc: 1, suite: vltmt-0}
|
||||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-1}
|
- {os: ubuntu-20.04, compiler: {cc: gcc-10, cxx: g++-10}, reloc: 1, suite: vltmt-1}
|
||||||
# Test relocated installation - on most common platform only
|
# Ubuntu 24.04 only on GCC; not passing on clang yet
|
||||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-0}
|
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-0}
|
||||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-1}
|
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-1}
|
||||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-2}
|
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-2}
|
||||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: dist-vlt-3}
|
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: dist-vlt-3}
|
||||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: vltmt-0}
|
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: vltmt-0}
|
||||||
- {os: ubuntu-22.04, compiler: { cc: gcc, cxx: g++ }, reloc: 1, suite: vltmt-1}
|
- {os: ubuntu-24.04, compiler: {cc: gcc, cxx: g++}, suite: vltmt-1}
|
||||||
runs-on: ${{ matrix.os }}
|
runs-on: ${{ matrix.os }}
|
||||||
name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.reloc && 'reloc | ' || '' }} ${{ matrix.suite }}
|
||||||
env:
|
env:
|
||||||
@@ -122,37 +122,37 @@ jobs:
|
|||||||
CC: ${{ matrix.compiler.cc }}
|
CC: ${{ matrix.compiler.cc }}
|
||||||
CXX: ${{ matrix.compiler.cxx }}
|
CXX: ${{ matrix.compiler.cxx }}
|
||||||
CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.reloc }}-${{ matrix.suite }}
|
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
|
VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Download tar archive
|
- name: Download tar archive
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||||
path: ${{ github.workspace }}
|
path: ${{ github.workspace }}
|
||||||
|
|
||||||
- name: Unpack tar archive
|
- name: Unpack tar archive
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||||
|
|
||||||
- name: Cache $CCACHE_DIR
|
- name: Cache $CCACHE_DIR
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
env:
|
env:
|
||||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache2
|
||||||
with:
|
with:
|
||||||
path: ${{ env.CCACHE_DIR }}
|
path: ${{ env.CCACHE_DIR }}
|
||||||
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
key: ${{ env.CACHE_KEY }}-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ env.CACHE_KEY }}-
|
${{ env.CACHE_KEY }}-
|
||||||
|
|
||||||
- name: Install test dependencies
|
- name: Install test dependencies
|
||||||
run: ./ci/ci-install.bash
|
run: ./ci/ci-install.bash
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
env:
|
env:
|
||||||
TESTS: ${{ matrix.suite }}
|
TESTS: ${{ matrix.suite }}
|
||||||
run: ./ci/ci-script.bash
|
run: ./ci/ci-script.bash
|
||||||
|
|
||||||
lint-py:
|
lint-py:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
@@ -161,21 +161,21 @@ jobs:
|
|||||||
CI_BUILD_STAGE_NAME: build
|
CI_BUILD_STAGE_NAME: build
|
||||||
CI_RUNS_ON: ubuntu-22.04
|
CI_RUNS_ON: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
|
|
||||||
- name: Install packages for build
|
- name: Install packages for build
|
||||||
run: ./ci/ci-install.bash
|
run: ./ci/ci-install.bash
|
||||||
|
|
||||||
# We use specific version numbers, otherwise a Python package
|
# We use specific version numbers, otherwise a Python package
|
||||||
# update may add a warning and break our build
|
# update may add a warning and break our build
|
||||||
- name: Install packages for lint
|
- 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
|
run: sudo pip3 install pylint==3.0.2 ruff==0.1.3 clang sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
run: autoconf && ./configure --enable-longtests --enable-ccwarn
|
run: autoconf && ./configure --enable-longtests --enable-ccwarn
|
||||||
|
|
||||||
- name: Lint
|
- name: Lint
|
||||||
run: make -k lint-py
|
run: make -k lint-py
|
||||||
|
|||||||
@@ -1,17 +1,16 @@
|
|||||||
|
---
|
||||||
# DESCRIPTION: Github actions config
|
# DESCRIPTION: Github actions config
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
#
|
||||||
name: Contributor Agreement
|
name: Contributor Agreement
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
Test:
|
Test:
|
||||||
name: "'docs/CONTRIBUTORS' was signed"
|
name: "'docs/CONTRIBUTORS' was signed"
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- run: test_regress/t/t_dist_contributors.pl
|
- run: test_regress/t/t_dist_contributors.py
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
---
|
||||||
# DESCRIPTION: Github actions config
|
# DESCRIPTION: Github actions config
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
@@ -6,7 +7,7 @@ name: coverage
|
|||||||
on:
|
on:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0' # weekly
|
- cron: '0 0 * * 0' # weekly
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: linux
|
CI_OS_NAME: linux
|
||||||
@@ -21,7 +22,6 @@ defaults:
|
|||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
|
||||||
|
|
||||||
Build:
|
Build:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
env:
|
env:
|
||||||
@@ -29,49 +29,36 @@ jobs:
|
|||||||
CI_RUNS_ON: ubuntu-22.04
|
CI_RUNS_ON: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
|
|
||||||
- name: Install packages for build
|
- name: Install packages for build
|
||||||
run: ./ci/ci-install.bash
|
run: ./ci/ci-install.bash
|
||||||
|
|
||||||
- name: Build
|
- name: Build
|
||||||
run: ./ci/ci-script.bash
|
run: ./ci/ci-script.bash
|
||||||
|
|
||||||
- name: Tar up repository
|
- name: Tar up repository
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
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: Upload tar archive
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||||
|
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||||
|
|
||||||
Test:
|
Test:
|
||||||
needs: Build
|
needs: Build
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
test:
|
test: [vlt-, vltmt-]
|
||||||
- vlt-
|
num: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||||
- vltmt-
|
|
||||||
num:
|
|
||||||
- 0
|
|
||||||
- 1
|
|
||||||
- 2
|
|
||||||
- 3
|
|
||||||
- 4
|
|
||||||
- 5
|
|
||||||
- 6
|
|
||||||
- 7
|
|
||||||
- 8
|
|
||||||
- 9
|
|
||||||
include:
|
include:
|
||||||
- { test: dist, num: '' }
|
- {test: dist, num: ''}
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
name: test-${{ matrix.test }}${{ matrix.num }}
|
name: test-${{ matrix.test }}${{ matrix.num }}
|
||||||
env:
|
env:
|
||||||
@@ -79,20 +66,27 @@ jobs:
|
|||||||
CI_RUNS_ON: ubuntu-22.04
|
CI_RUNS_ON: ubuntu-22.04
|
||||||
steps:
|
steps:
|
||||||
|
|
||||||
- name: Download tar archive
|
- name: Download tar archive
|
||||||
uses: actions/download-artifact@v4
|
uses: actions/download-artifact@v4
|
||||||
with:
|
with:
|
||||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||||
path: ${{ github.workspace }}
|
path: ${{ github.workspace }}
|
||||||
|
|
||||||
- name: Unpack tar archive
|
- name: Unpack tar archive
|
||||||
working-directory: ${{ github.workspace }}
|
working-directory: ${{ github.workspace }}
|
||||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||||
|
|
||||||
- name: Install test dependencies
|
- name: Install test dependencies
|
||||||
run: ./ci/ci-install.bash
|
run: ./ci/ci-install.bash
|
||||||
|
|
||||||
- name: Test
|
- name: Test
|
||||||
env:
|
env:
|
||||||
TESTS: coverage-${{ matrix.test }}${{ matrix.num }}
|
TESTS: coverage-${{ matrix.test }}${{ matrix.num }}
|
||||||
run: ./ci/ci-script.bash
|
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.
|
# Build and push verilator docker image when tags are pushed to the repository.
|
||||||
# The following variable(s) must be configured in the github repository:
|
# The following variable(s) must be configured in the github repository:
|
||||||
# DOCKER_HUB_NAMESPACE: docker hub namespace.
|
# DOCKER_HUB_NAMESPACE: docker hub namespace.
|
||||||
@@ -8,7 +9,7 @@ name: Build Verilator Container
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
tags: [ 'v*' ]
|
tags: ['v*']
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
inputs:
|
inputs:
|
||||||
manual_tag:
|
manual_tag:
|
||||||
@@ -34,52 +35,52 @@ jobs:
|
|||||||
# - "ci/docker/buildenv:verilator-buildenv"
|
# - "ci/docker/buildenv:verilator-buildenv"
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@v4
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
- name: Extract context variables
|
- name: Extract context variables
|
||||||
run: |
|
run: |
|
||||||
echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV"
|
echo "${{ matrix.contexts }}" | sed -r 's/(.*):.*/build_context=\1/' >> "$GITHUB_ENV"
|
||||||
echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV"
|
echo "${{ matrix.contexts }}" | sed -r 's/.*:(.*)/image_name=\1/' >> "$GITHUB_ENV"
|
||||||
echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV"
|
echo "git_tag=${GITHUB_REF#refs/*/}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Use manual tag
|
- name: Use manual tag
|
||||||
if: ${{ inputs.manual_tag }}
|
if: ${{ inputs.manual_tag }}
|
||||||
run: |
|
run: |
|
||||||
echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV"
|
echo "git_tag=${{ inputs.manual_tag }}" >> "$GITHUB_ENV"
|
||||||
|
|
||||||
- name: Docker meta
|
- name: Docker meta
|
||||||
id: docker_meta
|
id: docker_meta
|
||||||
uses: docker/metadata-action@v4
|
uses: docker/metadata-action@v4
|
||||||
with:
|
with:
|
||||||
images: |
|
images: |
|
||||||
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
${{ vars.DOCKER_HUB_NAMESPACE }}/${{ env.image_name }}
|
||||||
tags: |
|
tags: |
|
||||||
type=match,pattern=(v.*),group=1,enable=${{ startsWith(github.ref, 'refs/tags/v') }}
|
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=${{ inputs.manual_tag }},enable=${{ inputs.manual_tag != '' }}
|
||||||
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
type=raw,value=latest,enable=${{ inputs.add_latest_tag == true }}
|
||||||
|
|
||||||
- name: Set up QEMU
|
- name: Set up QEMU
|
||||||
uses: docker/setup-qemu-action@v2
|
uses: docker/setup-qemu-action@v2
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
uses: docker/setup-buildx-action@v2
|
uses: docker/setup-buildx-action@v2
|
||||||
with:
|
with:
|
||||||
buildkitd-flags: --debug
|
buildkitd-flags: --debug
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@v2
|
uses: docker/login-action@v2
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKER_HUB_USER }}
|
username: ${{ secrets.DOCKER_HUB_USER }}
|
||||||
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}
|
||||||
|
|
||||||
- name: Build and Push to Docker
|
- name: Build and Push to Docker
|
||||||
uses: docker/build-push-action@v4
|
uses: docker/build-push-action@v4
|
||||||
if: startsWith(github.ref, 'refs/tags/v')
|
if: startsWith(github.ref, 'refs/tags/v')
|
||||||
with:
|
with:
|
||||||
context: ${{ env.build_context }}
|
context: ${{ env.build_context }}
|
||||||
build-args: SOURCE_COMMIT=${{ env.git_tag }}
|
build-args: SOURCE_COMMIT=${{ env.git_tag }}
|
||||||
platforms: linux/arm64,linux/amd64
|
platforms: linux/arm64,linux/amd64
|
||||||
push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }}
|
push: ${{ !env.ACT && startsWith(github.ref, 'refs/tags/v') }}
|
||||||
tags: ${{ steps.docker_meta.outputs.tags }}
|
tags: ${{ steps.docker_meta.outputs.tags }}
|
||||||
labels: ${{ steps.docker_meta.outputs.labels }}
|
labels: ${{ steps.docker_meta.outputs.labels }}
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
|
---
|
||||||
# DESCRIPTION: Github actions config
|
# DESCRIPTION: Github actions config
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
#
|
||||||
name: format
|
name: format
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
pull_request_target:
|
pull_request_target:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
format:
|
format:
|
||||||
runs-on: ubuntu-22.04
|
runs-on: ubuntu-22.04
|
||||||
|
|||||||
@@ -1,55 +1,50 @@
|
|||||||
|
---
|
||||||
# DESCRIPTION: Github actions config
|
# DESCRIPTION: Github actions config
|
||||||
# This name is key to badges in README.rst, so we use the name build
|
# 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
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
#
|
||||||
name: msbuild
|
name: msbuild
|
||||||
|
|
||||||
on:
|
on:
|
||||||
push:
|
push:
|
||||||
pull_request:
|
pull_request:
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * 0' # weekly
|
- cron: 0 0 * * 0 # weekly
|
||||||
|
|
||||||
env:
|
env:
|
||||||
CI_OS_NAME: win
|
CI_OS_NAME: win
|
||||||
CI_COMMIT: ${{ github.sha }}
|
CI_COMMIT: ${{ github.sha }}
|
||||||
CCACHE_COMPRESS: 1
|
CCACHE_COMPRESS: 1
|
||||||
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
CCACHE_DIR: ${{ github.workspace }}/.ccache
|
||||||
CCACHE_LIMIT_MULTIPLE: 0.95
|
CCACHE_LIMIT_MULTIPLE: 0.95
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
working-directory: repo
|
working-directory: repo
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
|
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.ref || github.run_id }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
|
windows:
|
||||||
windows:
|
|
||||||
name: run on windows
|
name: run on windows
|
||||||
runs-on: windows-latest
|
runs-on: windows-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
path: repo
|
path: repo
|
||||||
- name: Cache $CCACHE_DIR
|
- name: Cache $CCACHE_DIR
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ env.CCACHE_DIR }}
|
path: ${{ env.CCACHE_DIR }}
|
||||||
key: msbuild-msvc-cmake
|
key: msbuild-msvc-cmake
|
||||||
- name: compile
|
- name: compile
|
||||||
env:
|
env:
|
||||||
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
WIN_FLEX_BISON: ${{ github.workspace }}/.ccache
|
||||||
run: ./ci/ci-win-compile.ps1
|
run: ./ci/ci-win-compile.ps1
|
||||||
- name: test build
|
- name: test build
|
||||||
run: ./ci/ci-win-test.ps1
|
run: ./ci/ci-win-test.ps1
|
||||||
- name: Zip up repository
|
- name: Zip up repository
|
||||||
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
run: Compress-Archive -LiteralPath install -DestinationPath verilator.zip
|
||||||
- name: Upload zip archive
|
- name: Upload zip archive
|
||||||
uses: actions/upload-artifact@v4
|
uses: actions/upload-artifact@v4
|
||||||
with:
|
with:
|
||||||
path: ${{ github.workspace }}/repo/verilator.zip
|
path: ${{ github.workspace }}/repo/verilator.zip
|
||||||
name: verilator-win.zip
|
name: verilator-win.zip
|
||||||
|
|||||||
+8
-4
@@ -29,14 +29,15 @@ dddrun*
|
|||||||
doxygen-doc
|
doxygen-doc
|
||||||
gdbrun*
|
gdbrun*
|
||||||
gmon.out
|
gmon.out
|
||||||
ncverilog.history
|
|
||||||
internals.txt
|
internals.txt
|
||||||
|
ncverilog.history
|
||||||
|
nohup.out
|
||||||
|
verilator-config-version.cmake
|
||||||
|
verilator-config.cmake
|
||||||
|
verilator.pc
|
||||||
verilator.txt
|
verilator.txt
|
||||||
verilator_bin*
|
verilator_bin*
|
||||||
verilator_coverage_bin*
|
verilator_coverage_bin*
|
||||||
verilator.pc
|
|
||||||
verilator-config.cmake
|
|
||||||
verilator-config-version.cmake
|
|
||||||
**/__pycache__/*
|
**/__pycache__/*
|
||||||
**/_build/*
|
**/_build/*
|
||||||
**/obj_dir/*
|
**/obj_dir/*
|
||||||
@@ -46,3 +47,6 @@ verilator-config-version.cmake
|
|||||||
/test_regress/snapshot/
|
/test_regress/snapshot/
|
||||||
xmverilog.*
|
xmverilog.*
|
||||||
xrun.history
|
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
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# See https://citation-file-format.github.io/
|
||||||
|
cff-version: 1.2.0
|
||||||
|
title: Verilator
|
||||||
|
message: >-
|
||||||
|
If you use this software, please cite it using the
|
||||||
|
metadata from this file.
|
||||||
|
type: software
|
||||||
|
authors:
|
||||||
|
- given-names: Wilson
|
||||||
|
family-names: Snyder
|
||||||
|
email: [email protected]
|
||||||
|
affiliation: Veripool
|
||||||
|
- given-names: Paul
|
||||||
|
family-names: Wasson
|
||||||
|
- given-names: Duane
|
||||||
|
family-names: Galbi
|
||||||
|
- name: 'et al'
|
||||||
|
repository-code: 'https://github.com/verilator/verilator'
|
||||||
|
url: 'https://verilator.org'
|
||||||
|
abstract: >-
|
||||||
|
The Verilator package converts Verilog and SystemVerilog hardware
|
||||||
|
description language (HDL) designs into a fast C++ or SystemC model
|
||||||
|
that, after compiling, can be executed. Verilator is not a
|
||||||
|
traditional simulator but a compiler.
|
||||||
|
license:
|
||||||
|
- LGPL-3.0-only
|
||||||
|
- Artistic-2.0
|
||||||
+74
-34
@@ -14,36 +14,44 @@
|
|||||||
|
|
||||||
cmake_minimum_required(VERSION 3.15)
|
cmake_minimum_required(VERSION 3.15)
|
||||||
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
||||||
project(Verilator
|
project(
|
||||||
VERSION 5.024
|
Verilator
|
||||||
|
VERSION 5.030
|
||||||
HOMEPAGE_URL https://verilator.org
|
HOMEPAGE_URL https://verilator.org
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
option(DEBUG_AND_RELEASE_AND_COVERAGE
|
option(
|
||||||
"Builds both the debug and release binaries, overriding CMAKE_BUILD_TYPE. Not supported under MSBuild.")
|
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)
|
find_package(Python3 COMPONENTS Interpreter)
|
||||||
set(PYTHON3 Python3::Interpreter)
|
set(PYTHON3 ${Python3_EXECUTABLE})
|
||||||
set(CMAKE_INSTALL_DATADIR ${CMAKE_INSTALL_PREFIX})
|
# See also CMake built-in; CMAKE_INSTALL_PREFIX is applied by the install command.
|
||||||
|
set(CMAKE_INSTALL_DATADIR .)
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
include(CMakePackageConfigHelpers)
|
include(CMakePackageConfigHelpers)
|
||||||
include(CheckStructHasMember)
|
include(CheckStructHasMember)
|
||||||
include(ExternalProject)
|
include(ExternalProject)
|
||||||
|
include(FindThreads)
|
||||||
|
|
||||||
if (NOT WIN32)
|
if(NOT WIN32)
|
||||||
message(WARNING "CMake support on Linux/OSX is experimental.")
|
message(WARNING "CMake support on Linux/OSX is experimental.")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (WIN32)
|
if(WIN32)
|
||||||
if (DEFINED ENV{WIN_FLEX_BISON})
|
if(DEFINED ENV{WIN_FLEX_BISON})
|
||||||
set(WIN_FLEX_BISON "$ENV{WIN_FLEX_BISON}")
|
set(WIN_FLEX_BISON "$ENV{WIN_FLEX_BISON}")
|
||||||
endif()
|
endif()
|
||||||
if (EXISTS ${WIN_FLEX_BISON})
|
if(EXISTS ${WIN_FLEX_BISON})
|
||||||
list(APPEND CMAKE_PREFIX_PATH ${WIN_FLEX_BISON})
|
list(APPEND CMAKE_PREFIX_PATH ${WIN_FLEX_BISON})
|
||||||
endif()
|
endif()
|
||||||
if (NOT WIN_FLEX_BISON)
|
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.")
|
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()
|
endif()
|
||||||
set(CMAKE_CXX_STANDARD 20)
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
endif()
|
endif()
|
||||||
@@ -51,20 +59,25 @@ endif()
|
|||||||
set(OBJCACHE "" CACHE STRING "Path for ccache, auto-detected if empty")
|
set(OBJCACHE "" CACHE STRING "Path for ccache, auto-detected if empty")
|
||||||
option(OBJCACHE_ENABLED "Compile Verilator with ccache" ON)
|
option(OBJCACHE_ENABLED "Compile Verilator with ccache" ON)
|
||||||
|
|
||||||
if (OBJCACHE_ENABLED)
|
if(OBJCACHE_ENABLED)
|
||||||
if (OBJCACHE STREQUAL "")
|
if(OBJCACHE STREQUAL "")
|
||||||
find_program(OBJCACHE_PATH ccache)
|
find_program(OBJCACHE_PATH ccache)
|
||||||
if (OBJCACHE_PATH STREQUAL "OBJCACHE_PATH-NOTFOUND")
|
if(OBJCACHE_PATH STREQUAL "OBJCACHE_PATH-NOTFOUND")
|
||||||
set(OBJCACHE_PATH "")
|
set(OBJCACHE_PATH "")
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
set(OBJCACHE_PATH "${OBJCACHE}")
|
set(OBJCACHE_PATH "${OBJCACHE}")
|
||||||
endif()
|
endif()
|
||||||
if (NOT OBJCACHE_PATH STREQUAL "")
|
if(NOT OBJCACHE_PATH STREQUAL "")
|
||||||
execute_process(COMMAND "${OBJCACHE_PATH}" --version
|
execute_process(
|
||||||
OUTPUT_VARIABLE objcache_version)
|
COMMAND "${OBJCACHE_PATH}" --version
|
||||||
|
OUTPUT_VARIABLE objcache_version
|
||||||
|
)
|
||||||
string(REGEX MATCH "[^\n\r]+" objcache_version "${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}")
|
set(CMAKE_CXX_COMPILER_LAUNCHER "${OBJCACHE_PATH}")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
@@ -75,8 +88,8 @@ find_package(FLEX)
|
|||||||
# Build
|
# Build
|
||||||
#set_property(GLOBAL PROPERTY JOB_POOLS one_job=1)
|
#set_property(GLOBAL PROPERTY JOB_POOLS one_job=1)
|
||||||
|
|
||||||
if (DEBUG_AND_RELEASE_AND_COVERAGE)
|
if(DEBUG_AND_RELEASE_AND_COVERAGE)
|
||||||
if (CMAKE_GENERATOR MATCHES "^Visual Studio ")
|
if(CMAKE_GENERATOR MATCHES "^Visual Studio ")
|
||||||
error("%Error: The DEBUG_AND_RELEASE_AND_COVERAGE option is not supported in MSBuild-based builds.")
|
error("%Error: The DEBUG_AND_RELEASE_AND_COVERAGE option is not supported in MSBuild-based builds.")
|
||||||
endif()
|
endif()
|
||||||
set(saved_build_type ${CMAKE_BUILD_TYPE})
|
set(saved_build_type ${CMAKE_BUILD_TYPE})
|
||||||
@@ -95,42 +108,69 @@ endif()
|
|||||||
|
|
||||||
set(PACKAGE_NAME ${PROJECT_NAME})
|
set(PACKAGE_NAME ${PROJECT_NAME})
|
||||||
set(PACKAGE_VERSION ${PROJECT_VERSION})
|
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_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)
|
install(
|
||||||
|
FILES ${CMAKE_CURRENT_BINARY_DIR}/include/verilated_config.h
|
||||||
configure_package_config_file(verilator-config.cmake.in verilator-config.cmake
|
DESTINATION include
|
||||||
INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}
|
)
|
||||||
|
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.cmake.in
|
||||||
configure_package_config_file(verilator-config-version.cmake.in verilator-config-version.cmake
|
verilator-config.cmake
|
||||||
INSTALL_DESTINATION ${CMAKE_INSTALL_PREFIX}
|
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
|
||||||
verilator_gantt
|
verilator_gantt
|
||||||
verilator_ccache_report
|
verilator_ccache_report
|
||||||
verilator_difftree
|
verilator_difftree
|
||||||
verilator_profcfunc
|
verilator_profcfunc
|
||||||
|
verilator_includer
|
||||||
)
|
)
|
||||||
install(PROGRAMS bin/${program} TYPE BIN)
|
install(PROGRAMS bin/${program} TYPE BIN)
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
install(DIRECTORY examples TYPE DATA FILES_MATCHING
|
install(
|
||||||
|
DIRECTORY examples
|
||||||
|
TYPE DATA
|
||||||
|
FILES_MATCHING
|
||||||
PATTERN "examples/*/*.[chv]*"
|
PATTERN "examples/*/*.[chv]*"
|
||||||
PATTERN "examples/*/Makefile*"
|
PATTERN "examples/*/Makefile*"
|
||||||
PATTERN "examples/*/CMakeLists.txt"
|
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_config.h"
|
||||||
PATTERN "include/verilated.mk"
|
|
||||||
PATTERN "include/*.[chv]"
|
PATTERN "include/*.[chv]"
|
||||||
PATTERN "include/*.cpp"
|
PATTERN "include/*.cpp"
|
||||||
PATTERN "include/*.sv"
|
PATTERN "include/*.sv"
|
||||||
|
|||||||
@@ -8,6 +8,255 @@ The changes in each Verilator version are described below. The
|
|||||||
contributors that suggested a given feature are shown in []. Thanks!
|
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
|
||||||
|
==========================
|
||||||
|
|
||||||
|
**Major:**
|
||||||
|
|
||||||
|
* Support constrained randomization with external solvers (#4947). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||||
|
|
||||||
|
**Minor:**
|
||||||
|
|
||||||
|
* Support `$psprintf` system function (#4314) (#5169). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||||
|
* Support 2D dynamic array initialization (#4700) (#5122). [Valentin Atepalikhin]
|
||||||
|
* Support __en/__out signals on top level inout ports (#4812) (#4856). [Paul Wright]
|
||||||
|
* Support empty queue as dynarray default value (#5055). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||||
|
* Support vpiInertialDelay (#5087). [Todd Strader]
|
||||||
|
* Support NBAs to arrays inside loops (#5092). [Geza Lore]
|
||||||
|
* Support parsing and otherwise ignoring inline constraints (#5126). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||||
|
* Support `inout` clocking items (#5160). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||||
|
* Support StructSel in unpacked array assignments (#5176). [Geza Lore]
|
||||||
|
* Add error on zero width select (#5028).
|
||||||
|
* Add CITATION.cff (#5057) (#5058). [Gijs Burghoorn]
|
||||||
|
* Add VPI eval needed tracking (#5065). [Todd Strader]
|
||||||
|
* Add `--localize-max-size` option and optimization (#5072).
|
||||||
|
* Add parameterless assert control system tasks (#5010). [Bartłomiej Chmiel]
|
||||||
|
* 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.]
|
||||||
|
* Fix missing flex include path variable (#4970) (#4971). [Christopher Taylor]
|
||||||
|
* Fix missing parameters with comma to be errors (#4979) (#5012). [Paul Swirhun]
|
||||||
|
* Fix 'experimental/coroutine' file not found on MacOS (#5030) (#5031) (#5151). [Paul Bowen-Huggett]
|
||||||
|
* Fix bound queue printing (#5032). [Aleksander Kiryk, Antmicro Ltd.]
|
||||||
|
* Fix consecutive zero-delays (#5038). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
|
* Fix attempted to destroy locked thread pool error (#5040). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||||
|
* Fix `$system` with string argument (#5042).
|
||||||
|
* Fix width extension on delays (#5043).
|
||||||
|
* Fix `$typename` on array.min and others (#5049). [Gökçe Aydos]
|
||||||
|
* Fix `make $(info)` which cannot be silenced (#5059). [Gökçe Aydos]
|
||||||
|
* Fix CMake builds to export VERILATOR_ROOT (#5063). [Michael Bikovitsky]
|
||||||
|
* Fix false ASSIGNIN on functions with explicit port map (#5069).
|
||||||
|
* Fix 4-state value support for $readmem (#5070) (#5078). [Ethan Sifferman]
|
||||||
|
* Fix DFG assertion with SystemC (#5076). [Geza Lore]
|
||||||
|
* Fix `$typename` string to be more standard (#5082) (#5083). [Andrew Nolte]
|
||||||
|
* Fix missed optimization in V3Delayed (#5089). [Geza Lore]
|
||||||
|
* Fix macro expansion in strings per 1800-2023 (#5094). [Geza Lore]
|
||||||
|
* Fix width extension of unpacked array select (#5095). [Varun Koyyalagunta]
|
||||||
|
* Fix MacOS missing <type_traits> header (#5096) (#5097). [Vito Gamberini]
|
||||||
|
* Fix assertion failure in V3Gate (#5101). [Yutetsu TAKATSUKASA]
|
||||||
|
* Fix aliases for forced port signals (#5105). [Geza Lore]
|
||||||
|
* Fix tracing interface functions (#5108). [Alex Solomatnikov]
|
||||||
|
* Fix method calls parsing in constraints (#5110). [Arkadiusz Kozdra, Antmicro Ltd.]
|
||||||
|
* Fix vpiInertialDelay for memories (#5113). [Todd Strader]
|
||||||
|
* Fix hierarchical compilation with nested -F (#5114) (#5124). [Alex Solomatnikov]
|
||||||
|
* Fix references to ports in forks (#5123). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
|
* Fix output C++ type error on change detect of I/O arrays (#5125) (#5131). [Pawel Jewstafjew]
|
||||||
|
* Fix x-valued parameters with `--x-assign unique` (#5129). [Ethan Sifferman]
|
||||||
|
* Fix overflow of string on VPI reads (#5145) (#5146). [Kaleb Barrett]
|
||||||
|
* Fix VerilatedVpiPutHolder class (#5156). [Kaleb Barrett]
|
||||||
|
* Fix extending out-of-range select (#5159) (#5164). [Geza Lore]
|
||||||
|
* Fix radix in width warnings (#5166). [Geza Lore]
|
||||||
|
* 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
|
Verilator 5.024 2024-04-05
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
@@ -56,9 +305,10 @@ Verilator 5.024 2024-04-05
|
|||||||
* Fix preprocessor to respect strings in joins (#5007).
|
* Fix preprocessor to respect strings in joins (#5007).
|
||||||
* Fix tracing class parameters (#5014).
|
* Fix tracing class parameters (#5014).
|
||||||
* Fix memory leaks (#5016). [Geza Lore]
|
* 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 internal error on missing pattern key (#5023).
|
||||||
* Fix tracing replicated hierarchical models (#5027).
|
* Fix tracing replicated hierarchical models (#5027).
|
||||||
|
* Fix false LIFETIME warning on `repeat` in `fork-join` (#5456).
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.022 2024-02-24
|
Verilator 5.022 2024-02-24
|
||||||
@@ -180,6 +430,7 @@ Verilator 5.020 2024-01-01
|
|||||||
* Fix dynamic NBA conditions (#4773). [Krzysztof Bieganski, Antmicro Ltd.]
|
* Fix dynamic NBA conditions (#4773). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
* Fix `V3Fork` stage to run only if `--timing` is set (#4778). [Krzysztof Bieganski, Antmicro Ltd.]
|
* Fix `V3Fork` stage to run only if `--timing` is set (#4778). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
* Fix max multiply width and add runtime assertions if too small. (#4781)
|
* Fix max multiply width and add runtime assertions if too small. (#4781)
|
||||||
|
* Fix select value too wide (#5148) (#5153). [Dercury]
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.018 2023-10-30
|
Verilator 5.018 2023-10-30
|
||||||
@@ -396,7 +647,7 @@ Verilator 5.012 2023-06-13
|
|||||||
* Fix wide structure VL_TOSTRING_W generation (#4188) (#4189). [Aylon Chaim Porat]
|
* 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 references to members of parameterized base classes (#4196). [Ryszard Rozak, Antmicro Ltd]
|
||||||
* Fix tracing undefined alignment (#4201) (#4288) [John Wehle]
|
* 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 dotted references in parameterized classes (#4206). [Ryszard Rozak, Antmicro Ltd]
|
||||||
* Fix bit selections under parameterized classes (#4210). [Ryszard Rozak, Antmicro Ltd]
|
* Fix bit selections under parameterized classes (#4210). [Ryszard Rozak, Antmicro Ltd]
|
||||||
* Fix duplicate std:: declaration with -I (#4215). [Harald Pretl]
|
* Fix duplicate std:: declaration with -I (#4215). [Harald Pretl]
|
||||||
@@ -552,7 +803,7 @@ Verilator 5.006 2023-01-22
|
|||||||
**Minor:**
|
**Minor:**
|
||||||
|
|
||||||
* Support clocking blocks (#3674). [Krzysztof Bieganski, Antmicro Ltd]
|
* 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 Windows-native builds using cmake (#3814). [Kritik Bhimani]
|
||||||
* Support p format for UnpackArray (#3877). [Aleksander Kiryk, Antmicro Ltd]
|
* Support p format for UnpackArray (#3877). [Aleksander Kiryk, Antmicro Ltd]
|
||||||
* Support property calls without parenthesis (#3879) (#3893). [Ryszard Rozak, Antmicro Ltd]
|
* Support property calls without parenthesis (#3879) (#3893). [Ryszard Rozak, Antmicro Ltd]
|
||||||
@@ -1443,6 +1694,7 @@ Verilator 4.026 2020-01-11
|
|||||||
* Fix expand optimization slowing --lint-only. Closes #2091. [Thomas Watts]
|
* Fix expand optimization slowing --lint-only. Closes #2091. [Thomas Watts]
|
||||||
* Fix %{number}s with strings. #2093. [agrobman]
|
* Fix %{number}s with strings. #2093. [agrobman]
|
||||||
* Fix shebang breaking some shells. Closes #2067. [zdave]
|
* 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
|
Verilator 4.024 2019-12-08
|
||||||
|
|||||||
+92
-34
@@ -52,6 +52,7 @@ INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
|||||||
INSTALL_DATA = @INSTALL_DATA@
|
INSTALL_DATA = @INSTALL_DATA@
|
||||||
MAKEINFO = makeinfo
|
MAKEINFO = makeinfo
|
||||||
POD2TEXT = pod2text
|
POD2TEXT = pod2text
|
||||||
|
PYTHON3 = @PYTHON3@
|
||||||
MKINSTALLDIRS = $(SHELL) $(srcdir)/src/mkinstalldirs
|
MKINSTALLDIRS = $(SHELL) $(srcdir)/src/mkinstalldirs
|
||||||
|
|
||||||
# Version (for docs/guide/conf.py)
|
# Version (for docs/guide/conf.py)
|
||||||
@@ -76,7 +77,7 @@ datadir = @datadir@
|
|||||||
# Directory in which to install documentation info files.
|
# Directory in which to install documentation info files.
|
||||||
infodir = @infodir@
|
infodir = @infodir@
|
||||||
|
|
||||||
# Directory in which to install package specific files
|
# Directory in which to install package-specific files
|
||||||
# Generally ${prefix}/share/verilator
|
# Generally ${prefix}/share/verilator
|
||||||
pkgdatadir = @pkgdatadir@
|
pkgdatadir = @pkgdatadir@
|
||||||
|
|
||||||
@@ -91,10 +92,12 @@ datarootdir = @datarootdir@
|
|||||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||||
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
||||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||||
|
CFG_WITH_SOLVER = @CFG_WITH_SOLVER@
|
||||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||||
|
|
||||||
#### End of system configuration section. ####
|
#### End of system configuration section. ####
|
||||||
######################################################################
|
######################################################################
|
||||||
|
# Main build targets
|
||||||
|
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
|
|
||||||
@@ -145,6 +148,9 @@ verilator_exe verilator_bin$(EXEEXT) verilator_bin_dbg$(EXEEXT) verilator_covera
|
|||||||
@echo "making verilator in src"
|
@echo "making verilator in src"
|
||||||
$(MAKE) -C src $(OBJCACHE_JOBS)
|
$(MAKE) -C src $(OBJCACHE_JOBS)
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Tests
|
||||||
|
|
||||||
.PHONY:msg_test
|
.PHONY:msg_test
|
||||||
msg_test: all_nomsg
|
msg_test: all_nomsg
|
||||||
@echo "Build complete!"
|
@echo "Build complete!"
|
||||||
@@ -155,7 +161,7 @@ msg_test: all_nomsg
|
|||||||
.PHONY: test
|
.PHONY: test
|
||||||
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
||||||
test: smoke-test test_regress
|
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)
|
# (because that allows it to run in parallel with other test_regress's)
|
||||||
else
|
else
|
||||||
test: smoke-test examples
|
test: smoke-test examples
|
||||||
@@ -167,8 +173,8 @@ endif
|
|||||||
@echo
|
@echo
|
||||||
|
|
||||||
smoke-test: all_nomsg
|
smoke-test: all_nomsg
|
||||||
test_regress/t/t_a1_first_cc.pl
|
test_regress/t/t_a1_first_cc.py
|
||||||
test_regress/t/t_a2_first_sc.pl
|
test_regress/t/t_a2_first_sc.py
|
||||||
|
|
||||||
test_regress: all_nomsg
|
test_regress: all_nomsg
|
||||||
$(MAKE) -C test_regress
|
$(MAKE) -C test_regress
|
||||||
@@ -182,6 +188,9 @@ examples: all_nomsg
|
|||||||
$(MAKE) -C $$p VERILATOR_ROOT=`pwd` || exit 10; \
|
$(MAKE) -C $$p VERILATOR_ROOT=`pwd` || exit 10; \
|
||||||
done
|
done
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Docs
|
||||||
|
|
||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
docs: info
|
docs: info
|
||||||
|
|
||||||
@@ -203,6 +212,20 @@ verilator.html:
|
|||||||
verilator.pdf: Makefile
|
verilator.pdf: Makefile
|
||||||
$(MAKE) -C docs verilator.pdf
|
$(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
|
# 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
|
# Don't put wildcards in these variables, it might cause an uninstall of other stuff
|
||||||
VL_INST_PUBLIC_SCRIPT_FILES = verilator \
|
VL_INST_PUBLIC_SCRIPT_FILES = verilator \
|
||||||
@@ -243,11 +266,15 @@ mkbindirs:
|
|||||||
installbin: | mkbindirs
|
installbin: | mkbindirs
|
||||||
cd $(srcdir)/bin; \
|
cd $(srcdir)/bin; \
|
||||||
for p in $(VL_INST_PUBLIC_SCRIPT_FILES) ; do \
|
for p in $(VL_INST_PUBLIC_SCRIPT_FILES) ; do \
|
||||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/bin/$$p; \
|
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
|
||||||
done
|
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; \
|
cd bin; \
|
||||||
for p in $(VL_INST_PUBLIC_BIN_FILES) ; do \
|
for p in $(VL_INST_PUBLIC_BIN_FILES) ; do \
|
||||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(pkgdatadir)/bin/$$p; \
|
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(bindir)/$$p; \
|
||||||
done
|
done
|
||||||
cd $(srcdir)/bin; \
|
cd $(srcdir)/bin; \
|
||||||
for p in $(VL_INST_PRIVATE_SCRIPT_FILES) ; do \
|
for p in $(VL_INST_PRIVATE_SCRIPT_FILES) ; do \
|
||||||
@@ -257,11 +284,11 @@ installbin: | mkbindirs
|
|||||||
installredirect: installbin | mkbindirs
|
installredirect: installbin | mkbindirs
|
||||||
cp ${srcdir}/bin/redirect ${srcdir}/bin/redirect.tmp
|
cp ${srcdir}/bin/redirect ${srcdir}/bin/redirect.tmp
|
||||||
perl -p -i -e 'use File::Spec;' \
|
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"
|
-e 's/RELPATH.*/"$$path";/g' -- "${srcdir}/bin/redirect.tmp"
|
||||||
cd $(srcdir)/bin; \
|
cd $(srcdir)/bin; \
|
||||||
for p in $(VL_INST_PUBLIC_SCRIPT_FILES) $(VL_INST_PUBLIC_BIN_FILES) ; do \
|
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
|
done
|
||||||
rm ${srcdir}/bin/redirect.tmp
|
rm ${srcdir}/bin/redirect.tmp
|
||||||
|
|
||||||
@@ -343,6 +370,19 @@ install-all: installbin installredirect installman installdata install-msg
|
|||||||
|
|
||||||
install-here: installman info
|
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
|
# Use --xml flag to see the cppcheck code to use for suppression
|
||||||
CPPCHECK1_CPP = $(wildcard $(srcdir)/include/*.cpp)
|
CPPCHECK1_CPP = $(wildcard $(srcdir)/include/*.cpp)
|
||||||
CPPCHECK2_CPP = $(wildcard $(srcdir)/examples/*/*.cpp)
|
CPPCHECK2_CPP = $(wildcard $(srcdir)/examples/*/*.cpp)
|
||||||
@@ -410,7 +450,8 @@ analyzer-include:
|
|||||||
-rm -rf examples/*/obj*
|
-rm -rf examples/*/obj*
|
||||||
scan-build $(MAKE) -k examples
|
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 = clang-format-14
|
||||||
CLANGFORMAT_FLAGS = -i
|
CLANGFORMAT_FLAGS = -i
|
||||||
@@ -421,6 +462,20 @@ clang-format:
|
|||||||
|| echo "*** You are not using clang-format-14, indents may differ from master's ***"
|
|| echo "*** You are not using clang-format-14, indents may differ from master's ***"
|
||||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
$(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 = \
|
PY_PROGRAMS = \
|
||||||
bin/verilator_ccache_report \
|
bin/verilator_ccache_report \
|
||||||
bin/verilator_difftree \
|
bin/verilator_difftree \
|
||||||
@@ -439,6 +494,7 @@ PY_PROGRAMS = \
|
|||||||
src/flexfix \
|
src/flexfix \
|
||||||
src/vlcovgen \
|
src/vlcovgen \
|
||||||
src/.gdbinit.py \
|
src/.gdbinit.py \
|
||||||
|
test_regress/*.py \
|
||||||
test_regress/t/*.pf \
|
test_regress/t/*.pf \
|
||||||
nodist/clang_check_attributes \
|
nodist/clang_check_attributes \
|
||||||
nodist/code_coverage \
|
nodist/code_coverage \
|
||||||
@@ -446,45 +502,55 @@ PY_PROGRAMS = \
|
|||||||
nodist/fuzzer/actual_fail \
|
nodist/fuzzer/actual_fail \
|
||||||
nodist/fuzzer/generate_dictionary \
|
nodist/fuzzer/generate_dictionary \
|
||||||
nodist/install_test \
|
nodist/install_test \
|
||||||
|
nodist/log_changes \
|
||||||
|
|
||||||
|
# Python files, subject to format but not lint
|
||||||
PY_FILES = \
|
PY_FILES = \
|
||||||
$(PY_PROGRAMS) \
|
$(PY_PROGRAMS) \
|
||||||
nodist/code_coverage.dat \
|
nodist/code_coverage.dat \
|
||||||
|
test_regress/t/*.py \
|
||||||
|
|
||||||
|
# Python files, test_regress tests
|
||||||
|
PY_TEST_FILES = \
|
||||||
|
test_regress/t/*.py \
|
||||||
|
|
||||||
YAPF = yapf3
|
YAPF = yapf3
|
||||||
YAPF_FLAGS = -i
|
YAPF_FLAGS = -i --parallel
|
||||||
|
|
||||||
yapf:
|
yapf:
|
||||||
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
|
$(YAPF) $(YAPF_FLAGS) $(PY_FILES)
|
||||||
|
|
||||||
|
GERSEMI = gersemi
|
||||||
|
GERSEMI_FLAGS = -i
|
||||||
|
|
||||||
|
format-cmake:
|
||||||
|
$(GERSEMI) $(GERSEMI_FLAGS) $(CMAKE_FILES)
|
||||||
|
|
||||||
PYLINT = pylint
|
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 = ruff
|
||||||
RUFF_FLAGS = check --ignore=E402,E501,E701
|
RUFF_FLAGS = check --ignore=E402,E501,E701
|
||||||
|
|
||||||
# "make -k" so can see all tool result errors
|
# "make -k" so can see all tool result errors
|
||||||
lint-py:
|
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:
|
lint-py-pylint:
|
||||||
$(PYLINT) $(PYLINT_FLAGS) $(PY_PROGRAMS)
|
$(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:
|
lint-py-ruff:
|
||||||
$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
|
$(RUFF) $(RUFF_FLAGS) $(PY_PROGRAMS)
|
||||||
|
|
||||||
format-pl-exec:
|
format-exec:
|
||||||
-chmod a+x test_regress/t/*.pl
|
-chmod a+x test_regress/t/*.py
|
||||||
|
|
||||||
install-msg:
|
######################################################################
|
||||||
@echo
|
# Configure
|
||||||
@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
|
|
||||||
|
|
||||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
||||||
|
|
||||||
@@ -505,6 +571,9 @@ else
|
|||||||
autoconf
|
autoconf
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
# Clean
|
||||||
|
|
||||||
maintainer-clean::
|
maintainer-clean::
|
||||||
@echo "This command is intended for maintainers to use;"
|
@echo "This command is intended for maintainers to use;"
|
||||||
@echo "rebuilding the deleted files requires autoconf."
|
@echo "rebuilding the deleted files requires autoconf."
|
||||||
@@ -535,17 +604,6 @@ distclean maintainer-clean::
|
|||||||
rm -f bin/verilator_bin* bin/verilator_coverage_bin*
|
rm -f bin/verilator_bin* bin/verilator_coverage_bin*
|
||||||
rm -f include/verilated.mk include/verilated_config.h
|
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
|
# Distributions
|
||||||
|
|
||||||
|
|||||||
+15
-14
@@ -1,21 +1,23 @@
|
|||||||
.. Github doesn't render images unless absolute URL
|
.. Github doesn't render images unless absolute URL
|
||||||
.. Do not know of a conditional tag, "only: github" nor "github display" works
|
.. Do not know of a conditional tag, "only: github" nor "github display" works
|
||||||
|
|
||||||
.. image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
|
|badge1| |badge2| |badge3| |badge4| |badge5| |badge6| |badge7| |badge8|
|
||||||
|
|
||||||
|
.. |badge1| image:: https://img.shields.io/badge/Website-Verilator.org-181717.svg
|
||||||
:target: https://verilator.org
|
:target: https://verilator.org
|
||||||
.. image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
|
.. |badge2| image:: https://img.shields.io/badge/License-LGPL%20v3-blue.svg
|
||||||
:target: https://www.gnu.org/licenses/lgpl-3.0
|
:target: https://www.gnu.org/licenses/lgpl-3.0
|
||||||
.. image:: https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg
|
.. |badge3| image:: https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg
|
||||||
:target: https://opensource.org/licenses/Artistic-2.0
|
:target: https://opensource.org/licenses/Artistic-2.0
|
||||||
.. image:: https://repology.org/badge/tiny-repos/verilator.svg?header=distro%20packages
|
.. |badge4| image:: https://repology.org/badge/tiny-repos/verilator.svg?header=distro%20packages
|
||||||
:target: https://repology.org/project/verilator/versions
|
:target: https://repology.org/project/verilator/versions
|
||||||
.. image:: https://img.shields.io/docker/pulls/verilator/verilator
|
.. |badge5| image:: https://img.shields.io/docker/pulls/verilator/verilator
|
||||||
:target: https://hub.docker.com/r/verilator/verilator
|
:target: https://hub.docker.com/r/verilator/verilator
|
||||||
.. image:: https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f
|
.. |badge6| image:: https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f
|
||||||
:target: https://www.codacy.com/gh/verilator/verilator
|
:target: https://www.codacy.com/gh/verilator/verilator
|
||||||
.. image:: https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg
|
.. |badge7| image:: https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg
|
||||||
:target: https://codecov.io/gh/verilator/verilator
|
:target: https://codecov.io/gh/verilator/verilator
|
||||||
.. image:: https://github.com/verilator/verilator/workflows/build/badge.svg
|
.. |badge8| image:: https://github.com/verilator/verilator/workflows/build/badge.svg
|
||||||
:target: https://github.com/verilator/verilator/actions?query=workflow%3Abuild
|
:target: https://github.com/verilator/verilator/actions?query=workflow%3Abuild
|
||||||
|
|
||||||
|
|
||||||
@@ -85,12 +87,11 @@ thread is about 100 times faster than interpreted Verilog simulators such
|
|||||||
as `Icarus Verilog`_. Another 2-10x speedup might be gained from
|
as `Icarus Verilog`_. Another 2-10x speedup might be gained from
|
||||||
multithreading (yielding 200-1000x total over interpreted simulators).
|
multithreading (yielding 200-1000x total over interpreted simulators).
|
||||||
|
|
||||||
Verilator has typically similar or better performance versus
|
Verilator has typically similar or better performance versus closed-source
|
||||||
closed-source Verilog simulators (e.g., Carbon Design Systems Carbonator,
|
Verilog simulators (e.g., Aldec Riviera-Pro, Cadence Incisive/NC-Verilog,
|
||||||
Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and
|
Mentor ModelSim/Questa, Synopsys VCS, VTOC, and Pragmatic CVer/CVC). But,
|
||||||
Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on
|
Verilator is open-sourced, so you can spend on computes rather than
|
||||||
computes rather than licenses. Thus, Verilator gives you the best
|
licenses. Thus, Verilator gives you the best simulation cycles/dollar.
|
||||||
simulation cycles/dollar.
|
|
||||||
|
|
||||||
|
|
||||||
Installation & Documentation
|
Installation & Documentation
|
||||||
|
|||||||
+12
-3
@@ -69,7 +69,9 @@ if (! GetOptions(
|
|||||||
pod2usage(-exitstatus => 2, -verbose => 0);
|
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 (defined $ENV{VERILATOR_ROOT}) {
|
||||||
if ((!-d $ENV{VERILATOR_ROOT}) || $verilator_root ne realpath($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";
|
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
|
--clk <signal-name> Mark specified signal as clock
|
||||||
--no-clk <signal-name> Prevent marking specified signal as clock
|
--no-clk <signal-name> Prevent marking specified signal as clock
|
||||||
--compiler <compiler-name> Tune for specified C++ compiler
|
--compiler <compiler-name> Tune for specified C++ compiler
|
||||||
|
--compiler-include Include additional header in the precompiled one
|
||||||
--converge-limit <loops> Tune convergence settle time
|
--converge-limit <loops> Tune convergence settle time
|
||||||
--coverage Enable all coverage
|
--coverage Enable all coverage
|
||||||
--coverage-line Enable line 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-tree-json <level> Enable dumping Ast .tree.json files at level
|
||||||
--dumpi-<srcfile> <level> Enable dumping everything in source file at level
|
--dumpi-<srcfile> <level> Enable dumping everything in source file at level
|
||||||
-E Preprocess, but do not compile
|
-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
|
--error-limit <value> Abort after this number of errors
|
||||||
--exe Link to create executable
|
--exe Link to create executable
|
||||||
--expand-limit <value> Set expand optimization limit
|
--expand-limit <value> Set expand optimization limit
|
||||||
@@ -375,6 +379,7 @@ detailed descriptions of these arguments.
|
|||||||
--get-supported <feature> Get if feature is supported
|
--get-supported <feature> Get if feature is supported
|
||||||
--help Show this help
|
--help Show this help
|
||||||
--hierarchical Enable hierarchical Verilation
|
--hierarchical Enable hierarchical Verilation
|
||||||
|
--hierarchical-params-file <name> Internal option that specifies parameters file for hier blocks
|
||||||
-I<dir> Directory to search for includes
|
-I<dir> Directory to search for includes
|
||||||
--if-depth <value> Tune IFDEPTH warning
|
--if-depth <value> Tune IFDEPTH warning
|
||||||
+incdir+<dir> Directory to search for includes
|
+incdir+<dir> Directory to search for includes
|
||||||
@@ -387,6 +392,7 @@ detailed descriptions of these arguments.
|
|||||||
--lib-create <name> Create a DPI library
|
--lib-create <name> Create a DPI library
|
||||||
+libext+<ext>+[ext]... Extensions for finding modules
|
+libext+<ext>+[ext]... Extensions for finding modules
|
||||||
--lint-only Lint, but do not make output
|
--lint-only Lint, but do not make output
|
||||||
|
--localize-max-size <value> Tune localize optimization variable size
|
||||||
--make <build-tool> Generate scripts for specified build tool
|
--make <build-tool> Generate scripts for specified build tool
|
||||||
-MAKEFLAGS <flags> Arguments to pass to make during --build
|
-MAKEFLAGS <flags> Arguments to pass to make during --build
|
||||||
--main Generate C++ main() file
|
--main Generate C++ main() file
|
||||||
@@ -401,13 +407,16 @@ detailed descriptions of these arguments.
|
|||||||
-O3 High-performance optimizations
|
-O3 High-performance optimizations
|
||||||
-O<optimization-letter> Selectable optimizations
|
-O<optimization-letter> Selectable optimizations
|
||||||
-o <executable> Name of final executable
|
-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 <statements> Split .cpp files into pieces
|
||||||
--output-split-cfuncs <statements> Split model functions
|
--output-split-cfuncs <statements> Split model functions
|
||||||
--output-split-ctrace <statements> Split tracing functions
|
--output-split-ctrace <statements> Split tracing functions
|
||||||
-P Disable line numbers and blanks with -E
|
-P Disable line numbers and blanks with -E
|
||||||
--pins-bv <bits> Specify types for top-level ports
|
--pins-bv <bits> Specify types for top-level ports
|
||||||
|
--pins-inout-enables Specify that __en and __out signals be created for inouts
|
||||||
--pins-sc-biguint Specify types for top-level ports
|
--pins-sc-biguint Specify types for top-level ports
|
||||||
--pins-sc-uint 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
|
--pins-uint8 Specify types for top-level ports
|
||||||
--no-pins64 Don't use uint64_t's for 33-64 bit sigs
|
--no-pins64 Don't use uint64_t's for 33-64 bit sigs
|
||||||
--pipe-filter <command> Filter all input through a script
|
--pipe-filter <command> Filter all input through a script
|
||||||
@@ -457,8 +466,8 @@ detailed descriptions of these arguments.
|
|||||||
--trace-coverage Enable tracing of coverage
|
--trace-coverage Enable tracing of coverage
|
||||||
--trace-depth <levels> Depth of tracing
|
--trace-depth <levels> Depth of tracing
|
||||||
--trace-fst Enable FST waveform creation
|
--trace-fst Enable FST waveform creation
|
||||||
--trace-max-array <depth> Maximum bit width for tracing
|
--trace-max-array <depth> Maximum array depth for tracing
|
||||||
--trace-max-width <width> Maximum array depth for tracing
|
--trace-max-width <width> Maximum bit width for tracing
|
||||||
--trace-params Enable tracing of parameters
|
--trace-params Enable tracing of parameters
|
||||||
--trace-structs Enable tracing structure names
|
--trace-structs Enable tracing structure names
|
||||||
--trace-threads <threads> Enable FST waveform creation on separate threads
|
--trace-threads <threads> Enable FST waveform creation on separate threads
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ parser = argparse.ArgumentParser(
|
|||||||
|
|
||||||
For documentation see
|
For documentation see
|
||||||
https://verilator.org/guide/latest/exe_verilator_ccache_report.html""",
|
https://verilator.org/guide/latest/exe_verilator_ccache_report.html""",
|
||||||
epilog=
|
epilog="""Copyright 2002-2024 by Wilson Snyder. This program is free software; you
|
||||||
"""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
|
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
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
Version 2.0.
|
Version 2.0.
|
||||||
@@ -67,30 +66,23 @@ else:
|
|||||||
wnames = max(len(_) for _ in results) + 1
|
wnames = max(len(_) for _ in results) + 1
|
||||||
wresults = max(len(_) for _ in results.values()) + 1
|
wresults = max(len(_) for _ in results.values()) + 1
|
||||||
for k in sorted(results.keys()):
|
for k in sorted(results.keys()):
|
||||||
args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format(
|
args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format(k,
|
||||||
k,
|
results[k],
|
||||||
results[k],
|
elapsed[k].total_seconds(),
|
||||||
elapsed[k].total_seconds(),
|
wnames=wnames,
|
||||||
wnames=wnames,
|
wresults=wresults))
|
||||||
wresults=wresults))
|
|
||||||
|
|
||||||
args.o.write("\nSummary:\n")
|
args.o.write("\nSummary:\n")
|
||||||
counts = collections.Counter(_ for _ in results.values())
|
counts = collections.Counter(_ for _ in results.values())
|
||||||
total = sum(counts.values())
|
total = sum(counts.values())
|
||||||
for k in sorted(counts.keys()):
|
for k in sorted(counts.keys()):
|
||||||
c = counts[k]
|
c = counts[k]
|
||||||
args.o.write("{:{width}}| {} ({:.2%})\n".format(k,
|
args.o.write("{:{width}}| {} ({:.2%})\n".format(k, c, c / total, width=wresults))
|
||||||
c,
|
|
||||||
c / total,
|
|
||||||
width=wresults))
|
|
||||||
|
|
||||||
args.o.write("\nLongest:\n")
|
args.o.write("\nLongest:\n")
|
||||||
longest = sorted(list(elapsed.items()),
|
longest = sorted(list(elapsed.items()), key=lambda kv: -kv[1].total_seconds())
|
||||||
key=lambda kv: -kv[1].total_seconds())
|
|
||||||
for i, (k, v) in enumerate(longest):
|
for i, (k, v) in enumerate(longest):
|
||||||
args.o.write("{:{width}}| {}s\n".format(k,
|
args.o.write("{:{width}}| {}s\n".format(k, v.total_seconds(), width=wnames))
|
||||||
v.total_seconds(),
|
|
||||||
width=wnames))
|
|
||||||
if i > 4:
|
if i > 4:
|
||||||
break
|
break
|
||||||
|
|
||||||
|
|||||||
@@ -154,9 +154,9 @@ verilator_coverage - Verilator coverage analyzer
|
|||||||
|
|
||||||
verilator_coverage --annotate <obj>
|
verilator_coverage --annotate <obj>
|
||||||
|
|
||||||
verilator_coverage -write merged.dat -read <datafiles>...
|
verilator_coverage -write merged.dat <datafiles>...
|
||||||
|
|
||||||
verilator_coverage -write-info merged.info -read <datafiles>...
|
verilator_coverage -write-info merged.info <datafiles>...
|
||||||
|
|
||||||
Verilator_coverage processes Verilated model-generated coverage reports.
|
Verilator_coverage processes Verilated model-generated coverage reports.
|
||||||
|
|
||||||
|
|||||||
@@ -47,8 +47,7 @@ def diff_dir(a, b):
|
|||||||
diff_file(a, b)
|
diff_file(a, b)
|
||||||
anyfile = True
|
anyfile = True
|
||||||
if not anyfile:
|
if not anyfile:
|
||||||
sys.stderr.write(
|
sys.stderr.write("%Warning: No .tree files found that have similar base names\n")
|
||||||
"%Warning: No .tree files found that have similar base names\n")
|
|
||||||
|
|
||||||
|
|
||||||
def diff_file(a, b):
|
def diff_file(a, b):
|
||||||
@@ -109,18 +108,14 @@ parser = argparse.ArgumentParser(
|
|||||||
Verilator_difftree is used for debugging Verilator tree output files.
|
Verilator_difftree is used for debugging Verilator tree output files.
|
||||||
It performs a diff between two files, or all files common between two
|
It performs a diff between two files, or all files common between two
|
||||||
directories, ignoring irrelevant pointer differences.""",
|
directories, ignoring irrelevant pointer differences.""",
|
||||||
epilog=
|
epilog="""Copyright 2005-2024 by Wilson Snyder. This program is free software; you
|
||||||
"""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
|
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
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
Version 2.0.
|
Version 2.0.
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||||
|
|
||||||
parser.add_argument('--debug',
|
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||||
action='store_const',
|
|
||||||
const=9,
|
|
||||||
help='enable debug')
|
|
||||||
parser.add_argument('--no-lineno',
|
parser.add_argument('--no-lineno',
|
||||||
action='store_false',
|
action='store_false',
|
||||||
help='do not show differences in line numbering')
|
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
|
Threads = collections.defaultdict(lambda: []) # List of records per thread id
|
||||||
Mtasks = collections.defaultdict(lambda: {'elapsed': 0, 'end': 0})
|
Mtasks = collections.defaultdict(lambda: {'elapsed': 0, 'end': 0})
|
||||||
Cpus = collections.defaultdict(lambda: {'mtask_time': 0})
|
Cpus = collections.defaultdict(lambda: {'mtask_time': 0})
|
||||||
Global = {
|
Global = {'args': {}, 'cpuinfo': collections.defaultdict(lambda: {}), 'stats': {}}
|
||||||
'args': {},
|
|
||||||
'cpuinfo': collections.defaultdict(lambda: {}),
|
|
||||||
'stats': {}
|
|
||||||
}
|
|
||||||
ElapsedTime = None # total elapsed time
|
ElapsedTime = None # total elapsed time
|
||||||
ExecGraphTime = 0 # total elapsed time excuting an exec graph
|
ExecGraphTime = 0 # total elapsed time excuting an exec graph
|
||||||
ExecGraphIntervals = [] # list of (start, end) pairs
|
ExecGraphIntervals = [] # list of (start, end) pairs
|
||||||
@@ -31,8 +27,7 @@ def read_data(filename):
|
|||||||
with open(filename, "r", encoding="utf8") as fh:
|
with open(filename, "r", encoding="utf8") as fh:
|
||||||
re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
|
re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
|
||||||
re_record = re.compile(r'^VLPROFEXEC (\S+) (\d+)(.*)$')
|
re_record = re.compile(r'^VLPROFEXEC (\S+) (\d+)(.*)$')
|
||||||
re_payload_mtaskBegin = re.compile(
|
re_payload_mtaskBegin = re.compile(r'id (\d+) predictStart (\d+) cpu (\d+)')
|
||||||
r'id (\d+) predictStart (\d+) cpu (\d+)')
|
|
||||||
re_payload_mtaskEnd = re.compile(r'id (\d+) predictCost (\d+)')
|
re_payload_mtaskEnd = re.compile(r'id (\d+) predictCost (\d+)')
|
||||||
|
|
||||||
re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*')
|
re_arg1 = re.compile(r'VLPROF arg\s+(\S+)\+([0-9.]*)\s*')
|
||||||
@@ -57,8 +52,7 @@ def read_data(filename):
|
|||||||
tick = int(tick)
|
tick = int(tick)
|
||||||
payload = payload.strip()
|
payload = payload.strip()
|
||||||
if kind == "SECTION_PUSH":
|
if kind == "SECTION_PUSH":
|
||||||
LongestVcdStrValueLength = max(LongestVcdStrValueLength,
|
LongestVcdStrValueLength = max(LongestVcdStrValueLength, len(payload))
|
||||||
len(payload))
|
|
||||||
SectionStack.append(payload)
|
SectionStack.append(payload)
|
||||||
Sections.append((tick, tuple(SectionStack)))
|
Sections.append((tick, tuple(SectionStack)))
|
||||||
elif kind == "SECTION_POP":
|
elif kind == "SECTION_POP":
|
||||||
@@ -66,15 +60,13 @@ def read_data(filename):
|
|||||||
SectionStack.pop()
|
SectionStack.pop()
|
||||||
Sections.append((tick, tuple(SectionStack)))
|
Sections.append((tick, tuple(SectionStack)))
|
||||||
elif kind == "MTASK_BEGIN":
|
elif kind == "MTASK_BEGIN":
|
||||||
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(
|
mtask, predict_start, ecpu = re_payload_mtaskBegin.match(payload).groups()
|
||||||
payload).groups()
|
|
||||||
mtask = int(mtask)
|
mtask = int(mtask)
|
||||||
predict_start = int(predict_start)
|
predict_start = int(predict_start)
|
||||||
ecpu = int(ecpu)
|
ecpu = int(ecpu)
|
||||||
mTaskThread[mtask] = thread
|
mTaskThread[mtask] = thread
|
||||||
records = Threads[thread]
|
records = Threads[thread]
|
||||||
assert not records or records[-1]['start'] <= records[-1][
|
assert not records or records[-1]['start'] <= records[-1]['end'] <= tick
|
||||||
'end'] <= tick
|
|
||||||
records.append({
|
records.append({
|
||||||
'start': tick,
|
'start': tick,
|
||||||
'mtask': mtask,
|
'mtask': mtask,
|
||||||
@@ -85,8 +77,7 @@ def read_data(filename):
|
|||||||
Mtasks[mtask]['thread'] = thread
|
Mtasks[mtask]['thread'] = thread
|
||||||
Mtasks[mtask]['predict_start'] = predict_start
|
Mtasks[mtask]['predict_start'] = predict_start
|
||||||
elif kind == "MTASK_END":
|
elif kind == "MTASK_END":
|
||||||
mtask, predict_cost = re_payload_mtaskEnd.match(
|
mtask, predict_cost = re_payload_mtaskEnd.match(payload).groups()
|
||||||
payload).groups()
|
|
||||||
mtask = int(mtask)
|
mtask = int(mtask)
|
||||||
predict_cost = int(predict_cost)
|
predict_cost = int(predict_cost)
|
||||||
begin = Mtasks[mtask]['begin']
|
begin = Mtasks[mtask]['begin']
|
||||||
@@ -163,8 +154,7 @@ def report():
|
|||||||
|
|
||||||
print("\nSummary:")
|
print("\nSummary:")
|
||||||
print(" Total elapsed time = {} rdtsc ticks".format(ElapsedTime))
|
print(" Total elapsed time = {} rdtsc ticks".format(ElapsedTime))
|
||||||
print(" Parallelized code = {:.2%} of elapsed time".format(
|
print(" Parallelized code = {:.2%} of elapsed time".format(ExecGraphTime / ElapsedTime))
|
||||||
ExecGraphTime / ElapsedTime))
|
|
||||||
print(" Total threads = %d" % nthreads)
|
print(" Total threads = %d" % nthreads)
|
||||||
print(" Total CPUs used = %d" % ncpus)
|
print(" Total CPUs used = %d" % ncpus)
|
||||||
print(" Total mtasks = %d" % len(Mtasks))
|
print(" Total mtasks = %d" % len(Mtasks))
|
||||||
@@ -176,15 +166,12 @@ def report():
|
|||||||
|
|
||||||
if nthreads > ncpus:
|
if nthreads > ncpus:
|
||||||
print()
|
print()
|
||||||
print("%%Warning: There were fewer CPUs (%d) than threads (%d)." %
|
print("%%Warning: There were fewer CPUs (%d) than threads (%d)." % (ncpus, nthreads))
|
||||||
(ncpus, nthreads))
|
|
||||||
print(" : See docs on use of numactl.")
|
print(" : See docs on use of numactl.")
|
||||||
else:
|
else:
|
||||||
if 'cpu_socket_cores_warning' in Global:
|
if 'cpu_socket_cores_warning' in Global:
|
||||||
print()
|
print()
|
||||||
print(
|
print("%Warning: Multiple threads scheduled on same hyperthreaded core.")
|
||||||
"%Warning: Multiple threads scheduled on same hyperthreaded core."
|
|
||||||
)
|
|
||||||
print(" : See docs on use of numactl.")
|
print(" : See docs on use of numactl.")
|
||||||
if 'cpu_sockets_warning' in Global:
|
if 'cpu_sockets_warning' in Global:
|
||||||
print()
|
print()
|
||||||
@@ -228,8 +215,7 @@ def report_mtasks():
|
|||||||
serialTime = ElapsedTime - ExecGraphTime
|
serialTime = ElapsedTime - ExecGraphTime
|
||||||
|
|
||||||
def subReport(elapsed, work):
|
def subReport(elapsed, work):
|
||||||
print(" Thread utilization = {:7.2%}".format(work /
|
print(" Thread utilization = {:7.2%}".format(work / (elapsed * nthreads)))
|
||||||
(elapsed * nthreads)))
|
|
||||||
print(" Speedup = {:6.3}x".format(work / elapsed))
|
print(" Speedup = {:6.3}x".format(work / elapsed))
|
||||||
|
|
||||||
print("\nParallelized code, measured:")
|
print("\nParallelized code, measured:")
|
||||||
@@ -256,8 +242,7 @@ def report_mtasks():
|
|||||||
if Mtasks[mtask]['elapsed'] > 0:
|
if Mtasks[mtask]['elapsed'] > 0:
|
||||||
if Mtasks[mtask]['predict_cost'] == 0:
|
if Mtasks[mtask]['predict_cost'] == 0:
|
||||||
Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below
|
Mtasks[mtask]['predict_cost'] = 1 # don't log(0) below
|
||||||
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] /
|
p2e_ratio = math.log(Mtasks[mtask]['predict_cost'] / Mtasks[mtask]['elapsed'])
|
||||||
Mtasks[mtask]['elapsed'])
|
|
||||||
p2e_ratios.append(p2e_ratio)
|
p2e_ratios.append(p2e_ratio)
|
||||||
|
|
||||||
if p2e_ratio > max_p2e:
|
if p2e_ratio > max_p2e:
|
||||||
@@ -269,18 +254,14 @@ def report_mtasks():
|
|||||||
|
|
||||||
print("\nMTask statistics:")
|
print("\nMTask statistics:")
|
||||||
print(" Longest mtask id = {}".format(long_mtask))
|
print(" Longest mtask id = {}".format(long_mtask))
|
||||||
print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".
|
print(" Longest mtask time = {:.2%} of time elapsed in parallelized code".format(
|
||||||
format(long_mtask_time / ExecGraphTime))
|
long_mtask_time / ExecGraphTime))
|
||||||
print(" min log(p2e) = %0.3f" % min_p2e, end="")
|
print(" min log(p2e) = %0.3f" % min_p2e, end="")
|
||||||
|
|
||||||
print(" from mtask %d (predict %d," %
|
print(" from mtask %d (predict %d," % (min_mtask, Mtasks[min_mtask]['predict_cost']), end="")
|
||||||
(min_mtask, Mtasks[min_mtask]['predict_cost']),
|
|
||||||
end="")
|
|
||||||
print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
|
print(" elapsed %d)" % Mtasks[min_mtask]['elapsed'])
|
||||||
print(" max log(p2e) = %0.3f" % max_p2e, end="")
|
print(" max log(p2e) = %0.3f" % max_p2e, end="")
|
||||||
print(" from mtask %d (predict %d," %
|
print(" from mtask %d (predict %d," % (max_mtask, Mtasks[max_mtask]['predict_cost']), end="")
|
||||||
(max_mtask, Mtasks[max_mtask]['predict_cost']),
|
|
||||||
end="")
|
|
||||||
print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
|
print(" elapsed %d)" % Mtasks[max_mtask]['elapsed'])
|
||||||
|
|
||||||
stddev = statistics.pstdev(p2e_ratios)
|
stddev = statistics.pstdev(p2e_ratios)
|
||||||
@@ -315,8 +296,8 @@ def report_cpus():
|
|||||||
model = cpuinfo['model_name']
|
model = cpuinfo['model_name']
|
||||||
|
|
||||||
print(" {:3d} | {:7.2%} / {:16d} | {:>6s} | {:>4s} | {}".format(
|
print(" {:3d} | {:7.2%} / {:16d} | {:>6s} | {:>4s} | {}".format(
|
||||||
cpu, Cpus[cpu]['mtask_time'] / ElapsedTime,
|
cpu, Cpus[cpu]['mtask_time'] / ElapsedTime, Cpus[cpu]['mtask_time'], socket, core,
|
||||||
Cpus[cpu]['mtask_time'], socket, core, model))
|
model))
|
||||||
|
|
||||||
if len(Global['cpu_sockets']) > 1:
|
if len(Global['cpu_sockets']) > 1:
|
||||||
Global['cpu_sockets_warning'] = True
|
Global['cpu_sockets_warning'] = True
|
||||||
@@ -366,8 +347,8 @@ def report_sections():
|
|||||||
|
|
||||||
def printTree(prefix, name, entries, tree):
|
def printTree(prefix, name, entries, tree):
|
||||||
print(" {:7.2%} | {:7.2%} | {:8} | {:10.2f} | {}".format(
|
print(" {:7.2%} | {:7.2%} | {:8} | {:10.2f} | {}".format(
|
||||||
treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2],
|
treeSum(tree) / ElapsedTime, tree[0] / ElapsedTime, tree[2], tree[2] / entries,
|
||||||
tree[2] / entries, prefix + name))
|
prefix + name))
|
||||||
for k in sorted(tree[1], key=lambda _: -treeSum(tree[1][_])):
|
for k in sorted(tree[1], key=lambda _: -treeSum(tree[1][_])):
|
||||||
printTree(prefix + " ", k, tree[2], tree[1][k])
|
printTree(prefix + " ", k, tree[2], tree[1][k])
|
||||||
|
|
||||||
@@ -438,10 +419,8 @@ def write_vcd(filename):
|
|||||||
addValue(code, start, mtask)
|
addValue(code, start, mtask)
|
||||||
addValue(code, end, None)
|
addValue(code, end, None)
|
||||||
|
|
||||||
tStart = sorted(_['start'] for records in Threads.values()
|
tStart = sorted(_['start'] for records in Threads.values() for _ in records)
|
||||||
for _ in records)
|
tEnd = sorted(_['end'] for records in Threads.values() for _ in records)
|
||||||
tEnd = sorted(_['end'] for records in Threads.values()
|
|
||||||
for _ in records)
|
|
||||||
|
|
||||||
# Predicted graph
|
# Predicted graph
|
||||||
for start, end in ExecGraphIntervals:
|
for start, end in ExecGraphIntervals:
|
||||||
@@ -455,11 +434,10 @@ def write_vcd(filename):
|
|||||||
# Predict mtasks that fill the time the execution occupied
|
# Predict mtasks that fill the time the execution occupied
|
||||||
for mtask in Mtasks:
|
for mtask in Mtasks:
|
||||||
thread = Mtasks[mtask]['thread']
|
thread = Mtasks[mtask]['thread']
|
||||||
pred_scaled_start = start + int(
|
pred_scaled_start = start + int(Mtasks[mtask]['predict_start'] * measured_scaling)
|
||||||
Mtasks[mtask]['predict_start'] * measured_scaling)
|
|
||||||
pred_scaled_end = start + int(
|
pred_scaled_end = start + int(
|
||||||
(Mtasks[mtask]['predict_start'] +
|
(Mtasks[mtask]['predict_start'] + Mtasks[mtask]['predict_cost']) *
|
||||||
Mtasks[mtask]['predict_cost']) * measured_scaling)
|
measured_scaling)
|
||||||
if pred_scaled_start == pred_scaled_end:
|
if pred_scaled_start == pred_scaled_end:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -545,8 +523,7 @@ Verilator_gantt creates a visual representation to help analyze Verilator
|
|||||||
|
|
||||||
For documentation see
|
For documentation see
|
||||||
https://verilator.org/guide/latest/exe_verilator_gantt.html""",
|
https://verilator.org/guide/latest/exe_verilator_gantt.html""",
|
||||||
epilog=
|
epilog="""Copyright 2018-2024 by Wilson Snyder. This program is free software; you
|
||||||
"""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
|
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
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
Version 2.0.
|
Version 2.0.
|
||||||
@@ -554,12 +531,8 @@ Version 2.0.
|
|||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||||
|
|
||||||
parser.add_argument('--debug', action='store_true', help='enable debug')
|
parser.add_argument('--debug', action='store_true', help='enable debug')
|
||||||
parser.add_argument('--no-vcd',
|
parser.add_argument('--no-vcd', help='disable creating vcd', action='store_true')
|
||||||
help='disable creating vcd',
|
parser.add_argument('--vcd', help='filename for vcd outpue', default='profile_exec.vcd')
|
||||||
action='store_true')
|
|
||||||
parser.add_argument('--vcd',
|
|
||||||
help='filename for vcd outpue',
|
|
||||||
default='profile_exec.vcd')
|
|
||||||
parser.add_argument('filename',
|
parser.add_argument('filename',
|
||||||
help='input profile_exec.dat filename to process',
|
help='input profile_exec.dat filename to process',
|
||||||
default='profile_exec.dat')
|
default='profile_exec.dat')
|
||||||
|
|||||||
+11
-22
@@ -34,9 +34,8 @@ def profcfunc(filename):
|
|||||||
|
|
||||||
# Older gprofs have no call column for single-call functions
|
# Older gprofs have no call column for single-call functions
|
||||||
# %time cumesec selfsec {stuff} name
|
# %time cumesec selfsec {stuff} name
|
||||||
match = re.match(
|
match = re.match(r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
|
||||||
r'^\s*([0-9.]+)\s+[0-9.]+\s+([0-9.]+)\s+[^a-zA-Z_]*([a-zA-Z_].*)$',
|
line)
|
||||||
line)
|
|
||||||
if match:
|
if match:
|
||||||
pct = float(match.group(1))
|
pct = float(match.group(1))
|
||||||
sec = float(match.group(2))
|
sec = float(match.group(2))
|
||||||
@@ -136,19 +135,15 @@ def profcfunc(filename):
|
|||||||
|
|
||||||
design_width = 1
|
design_width = 1
|
||||||
for func, func_item in vfuncs.items():
|
for func, func_item in vfuncs.items():
|
||||||
if design_width < len(func_item['design']):
|
design_width = max(design_width, len(func_item['design']))
|
||||||
design_width = len(func_item['design'])
|
|
||||||
|
|
||||||
print("Verilog code profile:")
|
print("Verilog code profile:")
|
||||||
print(" These are split into three categories:")
|
print(" These are split into three categories:")
|
||||||
print(" C++: Time in non-Verilated C++ code")
|
print(" C++: Time in non-Verilated C++ code")
|
||||||
print(" Prof: Time in profile overhead")
|
print(" Prof: Time in profile overhead")
|
||||||
print(" VBlock: Time attributable to a block in a" +
|
print(" VBlock: Time attributable to a block in a" + " Verilog file and line")
|
||||||
" Verilog file and line")
|
print(" VCommon: Time in a Verilated module," + " due to all parts of the design")
|
||||||
print(" VCommon: Time in a Verilated module," +
|
print(" VLib: Time in Verilated common libraries," + " called by the Verilated code")
|
||||||
" due to all parts of the design")
|
|
||||||
print(" VLib: Time in Verilated common libraries," +
|
|
||||||
" called by the Verilated code")
|
|
||||||
print()
|
print()
|
||||||
|
|
||||||
print(" % cumulative self ")
|
print(" % cumulative self ")
|
||||||
@@ -156,13 +151,11 @@ def profcfunc(filename):
|
|||||||
"s type filename and line number") % "design")
|
"s type filename and line number") % "design")
|
||||||
|
|
||||||
cume = 0
|
cume = 0
|
||||||
for func in sorted(vfuncs.keys(),
|
for func in sorted(vfuncs.keys(), key=lambda f: vfuncs[f]['sec'], reverse=True):
|
||||||
key=lambda f: vfuncs[f]['sec'],
|
|
||||||
reverse=True):
|
|
||||||
cume += vfuncs[func]['sec']
|
cume += vfuncs[func]['sec']
|
||||||
print(("%6.2f %9.2f %8.2f %10d %-" + str(design_width) + "s %s") %
|
print(("%6.2f %9.2f %8.2f %10d %-" + str(design_width) + "s %s") %
|
||||||
(vfuncs[func]['pct'], cume, vfuncs[func]['sec'],
|
(vfuncs[func]['pct'], cume, vfuncs[func]['sec'], vfuncs[func]['calls'],
|
||||||
vfuncs[func]['calls'], vfuncs[func]['design'], func))
|
vfuncs[func]['design'], func))
|
||||||
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
@@ -180,18 +173,14 @@ in each Verilog block.
|
|||||||
|
|
||||||
For documentation see
|
For documentation see
|
||||||
https://verilator.org/guide/latest/exe_verilator_profcfunc.html""",
|
https://verilator.org/guide/latest/exe_verilator_profcfunc.html""",
|
||||||
epilog=
|
epilog="""Copyright 2002-2024 by Wilson Snyder. This program is free software; you
|
||||||
"""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
|
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
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
Version 2.0.
|
Version 2.0.
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||||
|
|
||||||
parser.add_argument('--debug',
|
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||||
action='store_const',
|
|
||||||
const=9,
|
|
||||||
help='enable debug')
|
|
||||||
parser.add_argument('filename', help='input gprof output to process')
|
parser.add_argument('filename', help='input gprof output to process')
|
||||||
|
|
||||||
Args = parser.parse_args()
|
Args = parser.parse_args()
|
||||||
|
|||||||
+9
-16
@@ -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 ||
|
||||||
sudo apt-get install libgoogle-perftools-dev
|
sudo apt-get install libgoogle-perftools-dev
|
||||||
fi
|
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 ||
|
||||||
sudo apt-get install libsystemc libsystemc-dev
|
sudo apt-get install libsystemc libsystemc-dev
|
||||||
fi
|
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 ||
|
||||||
sudo apt-get install bear mold
|
sudo apt-get install bear mold
|
||||||
fi
|
fi
|
||||||
if [ "$COVERAGE" = 1 ]; then
|
|
||||||
yes yes | sudo cpan -fi Parallel::Forker
|
|
||||||
fi
|
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
elif [ "$CI_OS_NAME" = "osx" ]; then
|
||||||
brew update
|
brew update
|
||||||
brew install ccache perl gperftools
|
brew install ccache perl gperftools
|
||||||
@@ -92,32 +89,28 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||||||
sudo apt-get update ||
|
sudo apt-get update ||
|
||||||
sudo apt-get update
|
sudo apt-get update
|
||||||
# libfl-dev needed for internal coverage's test runs
|
# libfl-dev needed for internal coverage's test runs
|
||||||
sudo apt-get install gdb gtkwave lcov libfl-dev ccache jq ||
|
sudo apt-get install gdb gtkwave lcov libfl-dev ccache jq z3 ||
|
||||||
sudo apt-get install gdb gtkwave lcov libfl-dev ccache jq
|
sudo apt-get install gdb gtkwave lcov libfl-dev ccache jq z3
|
||||||
# Required for test_regress/t/t_dist_attributes.pl
|
# Required for test_regress/t/t_dist_attributes.py
|
||||||
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 python3-clang mold ||
|
sudo apt-get install python3-clang mold ||
|
||||||
sudo apt-get install python3-clang mold
|
sudo apt-get install python3-clang mold
|
||||||
fi
|
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 ||
|
||||||
sudo apt-get install libsystemc-dev
|
sudo apt-get install libsystemc-dev
|
||||||
fi
|
fi
|
||||||
elif [ "$CI_OS_NAME" = "osx" ]; then
|
elif [ "$CI_OS_NAME" = "osx" ]; then
|
||||||
brew update
|
brew update
|
||||||
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
|
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
|
||||||
brew install ccache perl jq
|
brew install ccache perl jq z3
|
||||||
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
||||||
# fst2vcd fails with "Could not open '<input file>', exiting."
|
# fst2vcd fails with "Could not open '<input file>', exiting."
|
||||||
sudo pkg install -y ccache gmake perl5 python3 jq
|
sudo pkg install -y ccache gmake perl5 python3 jq z3
|
||||||
else
|
else
|
||||||
fatal "Unknown os: '$CI_OS_NAME'"
|
fatal "Unknown os: '$CI_OS_NAME'"
|
||||||
fi
|
fi
|
||||||
# Common installs
|
# 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
|
install-vcddiff
|
||||||
# Workaround -fsanitize=address crash
|
# Workaround -fsanitize=address crash
|
||||||
sudo sysctl -w vm.mmap_rnd_bits=28
|
sudo sysctl -w vm.mmap_rnd_bits=28
|
||||||
|
|||||||
+6
-5
@@ -33,6 +33,7 @@ elif [ "$CI_OS_NAME" = "freebsd" ]; then
|
|||||||
else
|
else
|
||||||
fatal "Unknown os: '$CI_OS_NAME'"
|
fatal "Unknown os: '$CI_OS_NAME'"
|
||||||
fi
|
fi
|
||||||
|
NPROC=$(expr $NPROC '+' 1)
|
||||||
|
|
||||||
if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then
|
||||||
##############################################################################
|
##############################################################################
|
||||||
@@ -61,6 +62,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||||||
# Run tests
|
# Run tests
|
||||||
|
|
||||||
export VERILATOR_TEST_NO_CONTRIBUTORS=1 # Separate workflow check
|
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
|
if [ "$CI_OS_NAME" = "osx" ]; then
|
||||||
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
|
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
|
fi
|
||||||
|
|
||||||
# Run sanitize on Ubuntu 22.04 only
|
# 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
|
TEST_REGRESS=test_regress
|
||||||
if [ "$CI_RELOC" == 1 ]; then
|
if [ "$CI_RELOC" == 1 ]; then
|
||||||
@@ -192,13 +194,12 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then
|
|||||||
fatal "Unknown test: $TESTS"
|
fatal "Unknown test: $TESTS"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
# To see load average (1 minute, 5 minute, 15 minute)
|
||||||
|
uptime
|
||||||
# 22.04: ccache -s -v
|
# 22.04: ccache -s -v
|
||||||
ccache -s
|
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
|
else
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# Unknown build stage
|
# Unknown build stage
|
||||||
|
|||||||
+21
-8
@@ -1,13 +1,26 @@
|
|||||||
|
# DESCRIPTION: Verilator: CI Windows Power Shell - Compile Verilator
|
||||||
|
#
|
||||||
|
# Copyright 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
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
Set-PSDebug -Trace 1
|
||||||
|
|
||||||
if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) {
|
if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) {
|
||||||
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
git clone --depth 1 https://github.com/lexxmark/winflexbison
|
||||||
cd winflexbison
|
cd winflexbison
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. --install-prefix $PWD/../../../.ccache
|
cmake .. --install-prefix $PWD/../../../.ccache
|
||||||
cmake --build . --config Release -j 3
|
cmake --build . --config Release -j 3
|
||||||
cmake --install . --prefix $PWD/../../../.ccache
|
cmake --install . --prefix $PWD/../../../.ccache
|
||||||
cd ../..
|
cd ../..
|
||||||
}
|
}
|
||||||
|
|
||||||
mkdir build
|
mkdir build
|
||||||
cd build
|
cd build
|
||||||
cmake .. --install-prefix $PWD/../install
|
cmake .. --install-prefix $PWD/../install
|
||||||
|
|||||||
+17
-1
@@ -1,3 +1,16 @@
|
|||||||
|
# DESCRIPTION: Verilator: CI Windows Power Shell - Verilate a test
|
||||||
|
#
|
||||||
|
# Copyright 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
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
|
||||||
|
Set-PSDebug -Trace 1
|
||||||
|
|
||||||
cd install
|
cd install
|
||||||
$Env:VERILATOR_ROOT=$PWD
|
$Env:VERILATOR_ROOT=$PWD
|
||||||
cd examples/cmake_tracing_c
|
cd examples/cmake_tracing_c
|
||||||
@@ -5,6 +18,9 @@ mkdir build
|
|||||||
cd build
|
cd build
|
||||||
cmake ..
|
cmake ..
|
||||||
cmake --build . --config Release -j 3
|
cmake --build . --config Release -j 3
|
||||||
Release/example.exe
|
|
||||||
|
# TODO put this back in, see issue# 5163
|
||||||
|
# Release/example.exe
|
||||||
|
|
||||||
cd ..
|
cd ..
|
||||||
Remove-Item -path build -recurse
|
Remove-Item -path build -recurse
|
||||||
|
|||||||
Executable
BIN
Binary file not shown.
File diff suppressed because it is too large
Load Diff
@@ -43,6 +43,7 @@ RUN apt-get update \
|
|||||||
perl \
|
perl \
|
||||||
python3 \
|
python3 \
|
||||||
wget \
|
wget \
|
||||||
|
z3 \
|
||||||
zlib1g \
|
zlib1g \
|
||||||
zlib1g-dev \
|
zlib1g-dev \
|
||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
@@ -50,8 +51,6 @@ RUN apt-get update \
|
|||||||
|
|
||||||
WORKDIR /tmp
|
WORKDIR /tmp
|
||||||
|
|
||||||
RUN cpan install -fi Parallel::Forker
|
|
||||||
|
|
||||||
RUN git clone https://github.com/veripool/vcddiff.git && \
|
RUN git clone https://github.com/veripool/vcddiff.git && \
|
||||||
make -C vcddiff && \
|
make -C vcddiff && \
|
||||||
cp -p vcddiff/vcddiff /usr/local/bin/vcddiff && \
|
cp -p vcddiff/vcddiff /usr/local/bin/vcddiff && \
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
.. Copyright 2003-2024 by Wilson Snyder.
|
.. Copyright 2003-2024 by Wilson Snyder.
|
||||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
.. _Verilator Build Docker Container:
|
||||||
|
|
||||||
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
|
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.
|
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.:
|
easily compare results across versions, e.g.:
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|||||||
+15
-17
@@ -1,3 +1,4 @@
|
|||||||
|
---
|
||||||
# DESCRIPTION: codecov.io config
|
# DESCRIPTION: codecov.io config
|
||||||
#
|
#
|
||||||
# Copyright 2020-2024 by Wilson Snyder. This program is free software; you
|
# Copyright 2020-2024 by Wilson Snyder. This program is free software; you
|
||||||
@@ -8,31 +9,28 @@
|
|||||||
####################
|
####################
|
||||||
# Validate:
|
# Validate:
|
||||||
# curl --data-binary @codecov.yml https://codecov.io/validate
|
# curl --data-binary @codecov.yml https://codecov.io/validate
|
||||||
|
#
|
||||||
codecov:
|
codecov:
|
||||||
require_ci_to_pass: no
|
require_ci_to_pass: false
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
precision: 2
|
precision: 2
|
||||||
round: down
|
round: down
|
||||||
range: "50...100"
|
range: 50...100
|
||||||
ignore:
|
ignore:
|
||||||
- "ci"
|
- "ci" #
|
||||||
- "docs"
|
- "docs" #
|
||||||
- "examples"
|
- "examples" #
|
||||||
- "include/gtkwave"
|
- "include/gtkwave" #
|
||||||
- "include/vltstd"
|
- "include/vltstd" #
|
||||||
- "test_regress"
|
- "test_regress" #
|
||||||
|
|
||||||
parsers:
|
parsers:
|
||||||
gcov:
|
gcov:
|
||||||
branch_detection:
|
branch_detection:
|
||||||
conditional: yes
|
conditional: true
|
||||||
loop: yes
|
loop: true
|
||||||
method: no
|
method: false
|
||||||
macro: no
|
macro: false
|
||||||
|
|
||||||
comment:
|
comment:
|
||||||
layout: "reach,diff,flags,tree"
|
layout: "reach,diff,flags,tree"
|
||||||
behavior: default
|
behavior: default
|
||||||
require_changes: yes
|
require_changes: true
|
||||||
|
|||||||
+83
-31
@@ -5,12 +5,12 @@
|
|||||||
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
# When releasing, also update header of Changes file, and CmakeLists.txt,
|
# When releasing, also update header of Changes file, and CMakeLists.txt,
|
||||||
# and commit using "devel release" or "Version bump" message
|
# and commit using "devel release" or "Version bump" message
|
||||||
# Then 'make maintainer-dist'
|
# Then 'make maintainer-dist'
|
||||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||||
#AC_INIT([Verilator],[#.### devel])
|
#AC_INIT([Verilator],[#.### devel])
|
||||||
AC_INIT([Verilator],[5.024 2024-04-05],
|
AC_INIT([Verilator],[5.030 2024-10-27],
|
||||||
[https://verilator.org],
|
[https://verilator.org],
|
||||||
[verilator],[https://verilator.org])
|
[verilator],[https://verilator.org])
|
||||||
|
|
||||||
@@ -29,6 +29,9 @@ AC_DEFINE_UNQUOTED([PACKAGE_VERSION_STRING_CHAR],
|
|||||||
[Package version as a number])
|
[Package version as a number])
|
||||||
AC_SUBST(PACKAGE_VERSION_STRING_CHAR)
|
AC_SUBST(PACKAGE_VERSION_STRING_CHAR)
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
## Arguments/flag checking
|
||||||
|
|
||||||
# Ignore automake flags passed by Ubuntu builds
|
# Ignore automake flags passed by Ubuntu builds
|
||||||
AC_ARG_ENABLE([dependency-tracking],
|
AC_ARG_ENABLE([dependency-tracking],
|
||||||
[AS_HELP_STRING([--disable-dependency-tracking], [ignored])])
|
[AS_HELP_STRING([--disable-dependency-tracking], [ignored])])
|
||||||
@@ -134,6 +137,33 @@ AC_ARG_ENABLE([longtests],
|
|||||||
AC_SUBST(CFG_WITH_LONGTESTS)
|
AC_SUBST(CFG_WITH_LONGTESTS)
|
||||||
AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
||||||
|
|
||||||
|
AC_CHECK_PROG(HAVE_Z3,z3,yes)
|
||||||
|
AC_CHECK_PROG(HAVE_CVC5,cvc5,yes)
|
||||||
|
AC_CHECK_PROG(HAVE_CVC4,cvc4,yes)
|
||||||
|
|
||||||
|
# Special Substitutions - CFG_WITH_SOLVER
|
||||||
|
AC_MSG_CHECKING(for SMT solver)
|
||||||
|
AC_ARG_WITH([solver],
|
||||||
|
[AS_HELP_STRING([--with-solver='z3 --in'],
|
||||||
|
[set default SMT solver for constrained randomization])],
|
||||||
|
[CFG_WITH_SOLVER="${withval}"],
|
||||||
|
[CFG_WITH_SOLVER=no
|
||||||
|
if test "x$HAVE_Z3" = "xyes"; then
|
||||||
|
CFG_WITH_SOLVER="z3 --in"
|
||||||
|
elif test "x$HAVE_CVC5" = "xyes"; then
|
||||||
|
CFG_WITH_SOLVER="cvc5 --incremental"
|
||||||
|
elif test "x$HAVE_CVC4" = "xyes"; then
|
||||||
|
CFG_WITH_SOLVER="cvc4 --lang=smt2 --incremental"
|
||||||
|
fi]
|
||||||
|
)
|
||||||
|
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)
|
# Compiler flags (ensure they are not empty to avoid configure defaults)
|
||||||
CFLAGS="$CFLAGS "
|
CFLAGS="$CFLAGS "
|
||||||
CPPFLAGS="$CPPFLAGS "
|
CPPFLAGS="$CPPFLAGS "
|
||||||
@@ -160,24 +190,26 @@ if test "x$AR" = "x" ; then
|
|||||||
AC_MSG_ERROR([Cannot find "ar" in your PATH, please install it])
|
AC_MSG_ERROR([Cannot find "ar" in your PATH, please install it])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_PATH_PROG(PERL,perl)
|
AC_CHECK_PROG(PERL,perl,perl)
|
||||||
if test "x$PERL" = "x" ; then
|
if test "x$PERL" = "x" ; then
|
||||||
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
|
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
AC_PATH_PROG(PYTHON3,python3)
|
AC_CHECK_PROG(PYTHON3,python3,python3)
|
||||||
if test "x$PYTHON3" = "x" ; then
|
if test "x$PYTHON3" = "x" ; then
|
||||||
AC_MSG_ERROR([Cannot find "python3" in your PATH, please install it])
|
AC_MSG_ERROR([Cannot find "python3" in your PATH, please install it])
|
||||||
fi
|
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
|
if test "x$LEX" = "x" ; then
|
||||||
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
|
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
|
||||||
fi
|
fi
|
||||||
flex_version=$($LEX --version | head -1)
|
flex_version=$($LEX --version | head -1)
|
||||||
AC_MSG_RESULT([$LEX --version = $flex_version])
|
AC_MSG_RESULT([$LEX --version = $flex_version])
|
||||||
|
|
||||||
AC_PATH_PROG(YACC,bison)
|
AC_CHECK_PROG(YACC,bison,bison)
|
||||||
if test "x$YACC" = "x" ; then
|
if test "x$YACC" = "x" ; then
|
||||||
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
||||||
fi
|
fi
|
||||||
@@ -266,6 +298,43 @@ AC_DEFUN([_MY_CXX_CHECK_OPT],
|
|||||||
_MY_CXX_CHECK_IFELSE($2, $1="$$1 $2")
|
_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],
|
AC_DEFUN([_MY_LDLIBS_CHECK_FLAG],
|
||||||
[# _MY_LDLIBS_CHECK_FLAG(flag) -- Check if linker supports specific options
|
[# _MY_LDLIBS_CHECK_FLAG(flag) -- Check if linker supports specific options
|
||||||
# Set $_my_result appropriately
|
# Set $_my_result appropriately
|
||||||
@@ -351,32 +420,12 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wthread-safety)
|
|||||||
AC_SUBST(CFG_CXXFLAGS_WEXTRA)
|
AC_SUBST(CFG_CXXFLAGS_WEXTRA)
|
||||||
|
|
||||||
# Flags for coroutine support for dynamic scheduling
|
# Flags for coroutine support for dynamic scheduling
|
||||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts)
|
_MY_CXX_CHECK_CORO_SET(CFG_CXXFLAGS_COROUTINES, "")
|
||||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines)
|
_MY_CXX_CHECK_CORO_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts)
|
||||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_COROUTINES,-fcoroutines-ts -Wno-deprecated-experimental-coroutine)
|
_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)
|
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)
|
AC_SUBST(HAVE_COROUTINES)
|
||||||
|
|
||||||
# Flags for compiling Verilator internals including parser always
|
# Flags for compiling Verilator internals including parser always
|
||||||
@@ -584,6 +633,9 @@ AC_SUBST(HAVE_SYSTEMC)
|
|||||||
|
|
||||||
# Checks for system services
|
# Checks for system services
|
||||||
|
|
||||||
|
######################################################################
|
||||||
|
## Output
|
||||||
|
|
||||||
# Other install directories
|
# Other install directories
|
||||||
pkgdatadir=${datadir}/verilator
|
pkgdatadir=${datadir}/verilator
|
||||||
AC_SUBST(pkgdatadir)
|
AC_SUBST(pkgdatadir)
|
||||||
|
|||||||
@@ -7,22 +7,28 @@ Adam Bagley
|
|||||||
Adrian Sampson
|
Adrian Sampson
|
||||||
Adrien Le Masle
|
Adrien Le Masle
|
||||||
Ahmed El-Mahmoudy
|
Ahmed El-Mahmoudy
|
||||||
|
Aidan McNay
|
||||||
Aleksander Kiryk
|
Aleksander Kiryk
|
||||||
Alex Chadwick
|
Alex Chadwick
|
||||||
|
Alex Solomatnikov
|
||||||
Àlex Torregrosa
|
Àlex Torregrosa
|
||||||
Aliaksei Chapyzhenka
|
Aliaksei Chapyzhenka
|
||||||
Ameya Vikram Singh
|
Ameya Vikram Singh
|
||||||
|
Andrea Calabrese
|
||||||
Andreas Kuster
|
Andreas Kuster
|
||||||
Andrei Kostovski
|
Andrei Kostovski
|
||||||
Andrew Miloradovsky
|
Andrew Miloradovsky
|
||||||
Andrew Nolte
|
Andrew Nolte
|
||||||
Anthony Donlon
|
Anthony Donlon
|
||||||
Arkadiusz Kozdra
|
Arkadiusz Kozdra
|
||||||
|
Arthur Rosa
|
||||||
Aylon Chaim Porat
|
Aylon Chaim Porat
|
||||||
Bartłomiej Chmiel
|
Bartłomiej Chmiel
|
||||||
Cameron Kirk
|
Cameron Kirk
|
||||||
Chih-Mao Chen
|
Chih-Mao Chen
|
||||||
|
Chris Bachhuber
|
||||||
Chris Randall
|
Chris Randall
|
||||||
|
Christopher Taylor
|
||||||
Chuxuan Wang
|
Chuxuan Wang
|
||||||
Chykon
|
Chykon
|
||||||
Conor McCullough
|
Conor McCullough
|
||||||
@@ -33,14 +39,18 @@ David Ledger
|
|||||||
David Metz
|
David Metz
|
||||||
David Stanford
|
David Stanford
|
||||||
David Turner
|
David Turner
|
||||||
|
Dercury
|
||||||
Don Williamson
|
Don Williamson
|
||||||
Drew Ranck
|
Drew Ranck
|
||||||
Drew Taussig
|
Drew Taussig
|
||||||
Driss Hafdi
|
Driss Hafdi
|
||||||
Edgar E. Iglesias
|
Edgar E. Iglesias
|
||||||
|
Eric Müller
|
||||||
Eric Rippey
|
Eric Rippey
|
||||||
Ethan Sifferman
|
Ethan Sifferman
|
||||||
Eyck Jentzsch
|
Eyck Jentzsch
|
||||||
|
Furqan Nadir
|
||||||
|
Fabian Keßler
|
||||||
Fan Shupei
|
Fan Shupei
|
||||||
february cozzocrea
|
february cozzocrea
|
||||||
Felix Neumärker
|
Felix Neumärker
|
||||||
@@ -51,12 +61,14 @@ G-A. Kamendje
|
|||||||
Garrett Smith
|
Garrett Smith
|
||||||
Geza Lore
|
Geza Lore
|
||||||
Gianfranco Costamagna
|
Gianfranco Costamagna
|
||||||
|
Gijs Burghoorn
|
||||||
Glen Gibb
|
Glen Gibb
|
||||||
Gökçe Aydos
|
Gökçe Aydos
|
||||||
Graham Rushton
|
Graham Rushton
|
||||||
Guokai Chen
|
Guokai Chen
|
||||||
Gus Smith
|
Gus Smith
|
||||||
Gustav Svensk
|
Gustav Svensk
|
||||||
|
Han Qi
|
||||||
Harald Heckmann
|
Harald Heckmann
|
||||||
Hennadii Chernyshchyk
|
Hennadii Chernyshchyk
|
||||||
Howard Su
|
Howard Su
|
||||||
@@ -70,6 +82,7 @@ Iru Cai
|
|||||||
Ivan Vnučec
|
Ivan Vnučec
|
||||||
Iztok Jeras
|
Iztok Jeras
|
||||||
Jake Merdich
|
Jake Merdich
|
||||||
|
James Bailey
|
||||||
James Hanlon
|
James Hanlon
|
||||||
James Hutchinson
|
James Hutchinson
|
||||||
James Pallister
|
James Pallister
|
||||||
@@ -112,8 +125,11 @@ Kritik Bhimani
|
|||||||
Krzysztof Bieganski
|
Krzysztof Bieganski
|
||||||
Krzysztof Boronski
|
Krzysztof Boronski
|
||||||
Krzysztof Boroński
|
Krzysztof Boroński
|
||||||
|
Krzysztof Obłonczek
|
||||||
Kuba Ober
|
Kuba Ober
|
||||||
Larry Doolittle
|
Larry Doolittle
|
||||||
|
Liam Braun
|
||||||
|
Luca Colagrande
|
||||||
Ludwig Rogiers
|
Ludwig Rogiers
|
||||||
Lukasz Dalek
|
Lukasz Dalek
|
||||||
Maarten De Braekeleer
|
Maarten De Braekeleer
|
||||||
@@ -127,6 +143,7 @@ Marshal Qiao
|
|||||||
Martin Schmidt
|
Martin Schmidt
|
||||||
Martin Stadler
|
Martin Stadler
|
||||||
Matthew Ballance
|
Matthew Ballance
|
||||||
|
Michael Bikovitsky
|
||||||
Michael Killough
|
Michael Killough
|
||||||
Michaël Lefebvre
|
Michaël Lefebvre
|
||||||
Michal Czyz
|
Michal Czyz
|
||||||
@@ -136,18 +153,22 @@ Mladen Slijepcevic
|
|||||||
Morten Borup Petersen
|
Morten Borup Petersen
|
||||||
Mostafa Gamal
|
Mostafa Gamal
|
||||||
Nandu Raj
|
Nandu Raj
|
||||||
|
Nathan Graybeal
|
||||||
Nathan Kohagen
|
Nathan Kohagen
|
||||||
Nathan Myers
|
Nathan Myers
|
||||||
Nolan Poe
|
Nolan Poe
|
||||||
Oleh Maksymenko
|
Oleh Maksymenko
|
||||||
Patrick Stewart
|
Patrick Stewart
|
||||||
|
Paul Bowen-Huggett
|
||||||
Paul Swirhun
|
Paul Swirhun
|
||||||
Paul Wright
|
Paul Wright
|
||||||
|
Pawel Jewstafjew
|
||||||
Pawel Sagan
|
Pawel Sagan
|
||||||
Pengcheng Xu
|
Pengcheng Xu
|
||||||
Peter Debacker
|
Peter Debacker
|
||||||
Peter Horvath
|
Peter Horvath
|
||||||
Peter Monsson
|
Peter Monsson
|
||||||
|
Philip Axer
|
||||||
Philipp Wagner
|
Philipp Wagner
|
||||||
Pierre-Henri Horrein
|
Pierre-Henri Horrein
|
||||||
Pieter Kapsenberg
|
Pieter Kapsenberg
|
||||||
@@ -157,15 +178,18 @@ Quentin Corradi
|
|||||||
Rafal Kapuscik
|
Rafal Kapuscik
|
||||||
Rasfunk
|
Rasfunk
|
||||||
Raynard Qiao
|
Raynard Qiao
|
||||||
|
Ricardo Barbedo
|
||||||
Richard Myers
|
Richard Myers
|
||||||
Risto Pejašinović
|
Risto Pejašinović
|
||||||
Robert Balas
|
Robert Balas
|
||||||
Rupert Swarbrick
|
Rupert Swarbrick
|
||||||
|
Ryan Ziegler
|
||||||
Ryszard Rozak
|
Ryszard Rozak
|
||||||
Samuel Riedel
|
Samuel Riedel
|
||||||
Sean Cross
|
Sean Cross
|
||||||
Sebastien Van Cauwenberghe
|
Sebastien Van Cauwenberghe
|
||||||
Sergi Granell
|
Sergi Granell
|
||||||
|
Seth Pellegrino
|
||||||
Srinivasan Venkataramanan
|
Srinivasan Venkataramanan
|
||||||
Stefan Wallentowitz
|
Stefan Wallentowitz
|
||||||
Stephen Henry
|
Stephen Henry
|
||||||
@@ -185,6 +209,8 @@ Tudor Timi
|
|||||||
Tymoteusz Blazejczyk
|
Tymoteusz Blazejczyk
|
||||||
Udi Finkelstein
|
Udi Finkelstein
|
||||||
Unai Martinez-Corral
|
Unai Martinez-Corral
|
||||||
|
Udaya Raj Subedi
|
||||||
|
Valentin Atepalikhin
|
||||||
Varun Koyyalagunta
|
Varun Koyyalagunta
|
||||||
Vassilis Papaefstathiou
|
Vassilis Papaefstathiou
|
||||||
Veripool API Bot
|
Veripool API Bot
|
||||||
@@ -194,6 +220,8 @@ William D. Jones
|
|||||||
Wilson Snyder
|
Wilson Snyder
|
||||||
Xi Zhang
|
Xi Zhang
|
||||||
Yan Xu
|
Yan Xu
|
||||||
|
Yangyu Chen
|
||||||
|
Yilou Wang
|
||||||
Yinan Xu
|
Yinan Xu
|
||||||
Yoda Lee
|
Yoda Lee
|
||||||
Yossi Nivin
|
Yossi Nivin
|
||||||
@@ -205,3 +233,4 @@ Zhanglei Wang
|
|||||||
Zhou Shen
|
Zhou Shen
|
||||||
Zixi Li
|
Zixi Li
|
||||||
أحمد المحمودي
|
أحمد المحمودي
|
||||||
|
404allen404
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ SPHINXBUILD ?= sphinx-build
|
|||||||
SOURCEDIR = guide
|
SOURCEDIR = guide
|
||||||
BUILDDIR = _build
|
BUILDDIR = _build
|
||||||
|
|
||||||
SPHINXOPTS ?= -c guide
|
SPHINXOPTS ?= -c guide -j 4
|
||||||
ifneq ($(VERILATOR_ANALYTICS_ID),)
|
ifneq ($(VERILATOR_ANALYTICS_ID),)
|
||||||
SPHINXOPTS += -D html_theme_options.analytics_id=$(VERILATOR_ANALYTICS_ID)
|
SPHINXOPTS += -D html_theme_options.analytics_id=$(VERILATOR_ANALYTICS_ID)
|
||||||
endif
|
endif
|
||||||
|
|||||||
@@ -23,9 +23,7 @@ class VlSphinxExtract:
|
|||||||
outname = match.group(1)
|
outname = match.group(1)
|
||||||
print("Writing %s" % outname)
|
print("Writing %s" % outname)
|
||||||
fhw = open(outname, "w", encoding="utf8") # pylint: disable=consider-using-with
|
fhw = open(outname, "w", encoding="utf8") # pylint: disable=consider-using-with
|
||||||
fhw.write(
|
fhw.write(".. comment: generated by vl_sphinx_extract from " + filename + "\n")
|
||||||
".. comment: generated by vl_sphinx_extract from " +
|
|
||||||
filename + "\n")
|
|
||||||
fhw.write(".. code-block::\n")
|
fhw.write(".. code-block::\n")
|
||||||
elif re.match(r'^[=a-zA-Z0-9_]', line):
|
elif re.match(r'^[=a-zA-Z0-9_]', line):
|
||||||
fhw = None
|
fhw = None
|
||||||
@@ -39,18 +37,14 @@ parser = argparse.ArgumentParser(
|
|||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description="""Read a file and extract documentation data.""",
|
description="""Read a file and extract documentation data.""",
|
||||||
epilog=
|
epilog=""" Copyright 2021-2024 by Wilson Snyder. This package is free software;
|
||||||
""" 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
|
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
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
Version 2.0.
|
Version 2.0.
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||||
|
|
||||||
parser.add_argument('--debug',
|
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||||
action='store_const',
|
|
||||||
const=9,
|
|
||||||
help='enable debug')
|
|
||||||
parser.add_argument('path', help='path to extract from')
|
parser.add_argument('path', help='path to extract from')
|
||||||
Args = parser.parse_args()
|
Args = parser.parse_args()
|
||||||
|
|
||||||
|
|||||||
@@ -18,8 +18,7 @@ class VlSphinxFix:
|
|||||||
if os.path.isdir(path):
|
if os.path.isdir(path):
|
||||||
for basefile in os.listdir(path):
|
for basefile in os.listdir(path):
|
||||||
file = os.path.join(path, basefile)
|
file = os.path.join(path, basefile)
|
||||||
if ((basefile != ".") and (basefile != "..")
|
if ((basefile != ".") and (basefile != "..") and basefile not in self.SkipBasenames
|
||||||
and basefile not in self.SkipBasenames
|
|
||||||
and not os.path.islink(file)):
|
and not os.path.islink(file)):
|
||||||
self.process(file)
|
self.process(file)
|
||||||
elif re.search(r'\.(html|tex)$', path):
|
elif re.search(r'\.(html|tex)$', path):
|
||||||
@@ -54,18 +53,14 @@ parser = argparse.ArgumentParser(
|
|||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description="""Post-process Sphinx HTML.""",
|
description="""Post-process Sphinx HTML.""",
|
||||||
epilog=
|
epilog=""" Copyright 2021-2024 by Wilson Snyder. This package is free software;
|
||||||
""" 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
|
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
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
Version 2.0.
|
Version 2.0.
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||||
|
|
||||||
parser.add_argument('--debug',
|
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||||
action='store_const',
|
|
||||||
const=9,
|
|
||||||
help='enable debug')
|
|
||||||
parser.add_argument('path', help='path to edit')
|
parser.add_argument('path', help='path to edit')
|
||||||
Args = parser.parse_args()
|
Args = parser.parse_args()
|
||||||
|
|
||||||
|
|||||||
@@ -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"
|
filename = "../../Makefile"
|
||||||
with open(filename, "r", encoding="utf8") as fh:
|
with open(filename, "r", encoding="utf8") as fh:
|
||||||
for line in fh:
|
for line in fh:
|
||||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)",
|
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)", line)
|
||||||
line)
|
|
||||||
if match:
|
if match:
|
||||||
return match.group(1), match.group(2)
|
return match.group(1), match.group(2)
|
||||||
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +devel", line)
|
match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +devel", line)
|
||||||
@@ -75,8 +74,7 @@ extensions = []
|
|||||||
# directories to ignore when looking for source files.
|
# directories to ignore when looking for source files.
|
||||||
# This pattern also affects html_static_path and html_extra_path.
|
# This pattern also affects html_static_path and html_extra_path.
|
||||||
exclude_patterns = [
|
exclude_patterns = [
|
||||||
'_build', 'Thumbs.db', '.DS_Store', 'internals.rst', 'xml.rst', 'gen/ex_*',
|
'_build', 'Thumbs.db', '.DS_Store', 'internals.rst', 'xml.rst', 'gen/ex_*', 'CONTRIBUTING.rst'
|
||||||
'CONTRIBUTING.rst'
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Warn about refs
|
# Warn about refs
|
||||||
|
|||||||
@@ -407,6 +407,16 @@ only a couple of instructions.
|
|||||||
For signal callbacks to work the main loop of the program must call
|
For signal callbacks to work the main loop of the program must call
|
||||||
:code:`VerilatedVpi::callValueCbs()`.
|
:code:`VerilatedVpi::callValueCbs()`.
|
||||||
|
|
||||||
|
Verilator also tracks when the model state has been modified via the VPI with
|
||||||
|
an :code:`evalNeeded` flag. This flag can be checked with :code:`VerilatedVpi::evalNeeded()`
|
||||||
|
and it can be cleared with :code:`VerilatedVpi::clearEvalNeeded()`. Used together
|
||||||
|
it is possible to skip :code:`eval()` calls if no model state has been changed
|
||||||
|
since the last :code:`eval()`.
|
||||||
|
|
||||||
|
Any data written via :code:`vpi_put_value` with :code:`vpiInertialDelay` will
|
||||||
|
be deferred for later. These delayed values can be flushed to the model with
|
||||||
|
:code:`VerilatedVpi::doInertialPuts()`.
|
||||||
|
|
||||||
|
|
||||||
.. _VPI Example:
|
.. _VPI Example:
|
||||||
|
|
||||||
|
|||||||
+29
-11
@@ -23,24 +23,24 @@ Next, try the :vlopt:`--debug` option. This will enable additional
|
|||||||
internal assertions, and may help identify the problem.
|
internal assertions, and may help identify the problem.
|
||||||
|
|
||||||
Finally, reduce your code to the smallest possible routine that exhibits
|
Finally, reduce your code to the smallest possible routine that exhibits
|
||||||
the bug. Even better, create a test in the :file:`test_regress/t`
|
the bug (see: :ref:`Minimizing bug-inducing code`). Even better, create
|
||||||
directory, as follows:
|
a test in the :file:`test_regress/t` directory, as follows:
|
||||||
|
|
||||||
.. code-block:: bash
|
.. code-block:: bash
|
||||||
|
|
||||||
cd test_regress
|
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
|
cp -p t/t_EXAMPLE.v t/t_BUG.v
|
||||||
|
|
||||||
There are many hints on how to write a good test in the
|
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
|
.. code-block:: bash
|
||||||
|
|
||||||
cd $VERILATOR_ROOT # Need the original distribution kit
|
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
|
in the Verilog code there; just make sure it retains the single clk input
|
||||||
and no outputs. Now, the following should fail:
|
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 $VERILATOR_ROOT # Need the original distribution kit
|
||||||
cd test_regress
|
cd test_regress
|
||||||
t/t_BUG.pl # Run on Verilator
|
t/t_BUG.py # Run on Verilator
|
||||||
t/t_BUG.pl --debug # Run on Verilator, passing --debug to Verilator
|
t/t_BUG.py --debug # Run on Verilator, passing --debug to Verilator
|
||||||
t/t_BUG.pl --vcs # Run on VCS simulator
|
t/t_BUG.py --vcs # Run on VCS simulator
|
||||||
t/t_BUG.pl --nc|--iv|--ghdl # Likewise on other simulators
|
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
|
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
|
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
|
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
|
Finally, report the bug at `Verilator Issues
|
||||||
<https://verilator.org/issues>`_. The bug will become publicly visible; if
|
<https://verilator.org/issues>`_. The bug will become publicly visible; if
|
||||||
this is unacceptable, mail the bug report to ``[email protected]``.
|
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
|
.. Contributing
|
||||||
.. ============
|
.. ============
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ C++14 compiler support
|
|||||||
Verilated models with --no-timing.
|
Verilated models with --no-timing.
|
||||||
|
|
||||||
Verilator will require C++20 or newer compilers for both compiling
|
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
|
XML output
|
||||||
Verilator currently supports XML parser output (enabled with `--xml-only`).
|
Verilator currently supports XML parser output (enabled with `--xml-only`).
|
||||||
|
|||||||
@@ -118,6 +118,12 @@ associated programs.
|
|||||||
|
|
||||||
See :ref:`Installation` for more details.
|
See :ref:`Installation` for more details.
|
||||||
|
|
||||||
|
.. option:: VERILATOR_SOLVER
|
||||||
|
|
||||||
|
If set, the command to run as a constrained randomization backend, such
|
||||||
|
as :command:`cvc4 --lang=smt2 --incremental`. If not specified, it will use
|
||||||
|
the one supplied or found during configure, or :command:`z3 --in` if empty.
|
||||||
|
|
||||||
.. option:: VERILATOR_VALGRIND
|
.. option:: VERILATOR_VALGRIND
|
||||||
|
|
||||||
If set, the command to run when using the :vlopt:`--valgrind` option, such as
|
If set, the command to run when using the :vlopt:`--valgrind` option, such as
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ Now, let's create an example Verilog, and SystemC wrapper file:
|
|||||||
|
|
||||||
cat >sc_main.cpp <<'EOF'
|
cat >sc_main.cpp <<'EOF'
|
||||||
#include "Vour.h"
|
#include "Vour.h"
|
||||||
|
using namespace sc_core;
|
||||||
int sc_main(int argc, char** argv) {
|
int sc_main(int argc, char** argv) {
|
||||||
Verilated::commandArgs(argc, argv);
|
Verilated::commandArgs(argc, argv);
|
||||||
sc_clock clk{"clk", 10, SC_NS, 0.5, 3, SC_NS, true};
|
sc_clock clk{"clk", 10, SC_NS, 0.5, 3, SC_NS, true};
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ Summary:
|
|||||||
.. option:: +verilator+error+limit+<value>
|
.. option:: +verilator+error+limit+<value>
|
||||||
|
|
||||||
Set number of non-fatal errors (e.g. assertion failures) before exiting
|
Set number of non-fatal errors (e.g. assertion failures) before exiting
|
||||||
simulation runtime. Also affects number of $stop calls needed before
|
simulation runtime. Also affects number of `$stop` calls needed before
|
||||||
exit. Defaults to 1.
|
exit. Does not affect `$fatal`. Defaults to 1.
|
||||||
|
|
||||||
.. option:: +verilator+help
|
.. option:: +verilator+help
|
||||||
|
|
||||||
|
|||||||
@@ -222,6 +222,13 @@ Summary:
|
|||||||
expressions into sub-expressions to avoid error C1009, and breaking
|
expressions into sub-expressions to avoid error C1009, and breaking
|
||||||
deep blocks into functions to avoid error C1061.
|
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>
|
.. option:: --converge-limit <loops>
|
||||||
|
|
||||||
Rarely needed. Specifies the maximum number of runtime iterations
|
Rarely needed. Specifies the maximum number of runtime iterations
|
||||||
@@ -476,6 +483,12 @@ Summary:
|
|||||||
See also :vlopt:`--dump-defines`, :vlopt:`-P`, and
|
See also :vlopt:`--dump-defines`, :vlopt:`-P`, and
|
||||||
:vlopt:`--pp-comments` options.
|
: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>
|
.. option:: --error-limit <value>
|
||||||
|
|
||||||
After this number of errors are encountered during Verilator run, exit.
|
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
|
:option:`/*verilator&32;hier_block*/` metacomment is ignored. See
|
||||||
:ref:`Hierarchical Verilation`.
|
: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>
|
.. option:: -I<dir>
|
||||||
|
|
||||||
See :vlopt:`-y`.
|
See :vlopt:`-y`.
|
||||||
@@ -817,6 +837,11 @@ Summary:
|
|||||||
If the design is not to be completely Verilated, see also the
|
If the design is not to be completely Verilated, see also the
|
||||||
:vlopt:`--bbox-sys` and :vlopt:`--bbox-unsup` options.
|
:vlopt:`--bbox-sys` and :vlopt:`--bbox-unsup` options.
|
||||||
|
|
||||||
|
.. option:: --localize-max-size <value>
|
||||||
|
|
||||||
|
Rarely needed. Set the maximum variable size in bytes for it to be
|
||||||
|
subject to localizing-to-stack optimization. Defaults to 1024.
|
||||||
|
|
||||||
.. option:: --make <build-tool>
|
.. option:: --make <build-tool>
|
||||||
|
|
||||||
Generates a script for the specified build tool.
|
Generates a script for the specified build tool.
|
||||||
@@ -933,6 +958,22 @@ Summary:
|
|||||||
delayed assignments. This option should only be used when suggested by
|
delayed assignments. This option should only be used when suggested by
|
||||||
the developers.
|
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>
|
.. option:: --output-split <statements>
|
||||||
|
|
||||||
Enables splitting the output .cpp files into multiple outputs. When a
|
Enables splitting the output .cpp files into multiple outputs. When a
|
||||||
@@ -985,6 +1026,13 @@ Summary:
|
|||||||
:option:`/*verilator&32;sc_bv*/` metacomment to select specific ports to
|
:option:`/*verilator&32;sc_bv*/` metacomment to select specific ports to
|
||||||
be sc_bv.
|
be sc_bv.
|
||||||
|
|
||||||
|
.. option:: --pins-inout-enables
|
||||||
|
|
||||||
|
Specifies that the __en and __out outputs will always be created for
|
||||||
|
inouts in the top-level module. The __en variable has a one in a bit
|
||||||
|
position to indicate the corresponding bit of the __out variable has
|
||||||
|
a value being driven from within the Verilated model.
|
||||||
|
|
||||||
.. option:: --pins-sc-uint
|
.. option:: --pins-sc-uint
|
||||||
|
|
||||||
Specifies SystemC inputs/outputs greater than 2 bits wide should use
|
Specifies SystemC inputs/outputs greater than 2 bits wide should use
|
||||||
@@ -992,6 +1040,10 @@ Summary:
|
|||||||
:vlopt:`--pins-sc-biguint` combination, it results in sc_uint being used
|
: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.
|
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
|
.. option:: --pins-sc-biguint
|
||||||
|
|
||||||
Specifies SystemC inputs/outputs greater than 65 bits wide should use
|
Specifies SystemC inputs/outputs greater than 65 bits wide should use
|
||||||
@@ -1732,9 +1784,9 @@ Summary:
|
|||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
This option applies only to values explicitly written as X
|
This option applies only to values explicitly written as X in modules
|
||||||
in modules (not classes) in the Verilog source code. Initial values
|
(not classes, nor parameters) in the Verilog source code. Initial
|
||||||
of clocks are set to 0 unless `--x-initial-edge` is
|
values of clocks are set to 0 unless `--x-initial-edge` is
|
||||||
specified. Initial values of all other state holding variables are
|
specified. Initial values of all other state holding variables are
|
||||||
controlled with `--x-initial`.
|
controlled with `--x-initial`.
|
||||||
|
|
||||||
@@ -1873,8 +1925,12 @@ Configuration Files
|
|||||||
|
|
||||||
In addition to the command line, warnings and other features for the
|
In addition to the command line, warnings and other features for the
|
||||||
:command:`verilator` command may be controlled with configuration files,
|
:command:`verilator` command may be controlled with configuration files,
|
||||||
typically named with the .vlt extension (what makes it a configuration file
|
typically named with the `.vlt` extension (what makes it a configuration
|
||||||
is the :option:`\`verilator_config` directive). An example:
|
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
|
.. code-block:: sv
|
||||||
|
|
||||||
@@ -1967,6 +2023,13 @@ The grammar of configuration commands is as follows:
|
|||||||
that the setting is ignored unless the :vlopt:`--hierarchical` option is
|
that the setting is ignored unless the :vlopt:`--hierarchical` option is
|
||||||
specified. See :ref:`Hierarchical Verilation`.
|
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>"
|
.. option:: inline -module "<modulename>"
|
||||||
|
|
||||||
Specifies the module may be inlined into any modules that use this
|
Specifies the module may be inlined into any modules that use this
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ verilator_coverage Example Usage
|
|||||||
|
|
||||||
verilator_coverage --annotate <obj>
|
verilator_coverage --annotate <obj>
|
||||||
|
|
||||||
verilator_coverage -write merged.dat -read <datafiles>...
|
verilator_coverage -write merged.dat <datafiles>...
|
||||||
|
|
||||||
verilator_coverage -write-info merged.info -read <datafiles>...
|
verilator_coverage -write-info merged.info <datafiles>...
|
||||||
|
|
||||||
|
|
||||||
verilator_coverage Arguments
|
verilator_coverage Arguments
|
||||||
@@ -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
|
Specifies the directory name to which source files with annotated coverage
|
||||||
data should be written.
|
data should be written.
|
||||||
|
|
||||||
Converting from the Verilator coverage data format to the info format is
|
Points are children of each line coverage- branches or toggle points.
|
||||||
lossy; the info will have all forms of coverage merged line coverage, and
|
When point counts are aggregated into a line, the minimum and maximum counts
|
||||||
if there are multiple coverage points on a single line they will merge.
|
are used to determine the status of the line (complete, partial, failing)
|
||||||
The minimum coverage across all merged points will be used to report
|
The count is equal to the maximum of the points.
|
||||||
coverage of the line.
|
|
||||||
|
|
||||||
Coverage data is annotated at the beginning of the line and is formatted
|
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
|
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.
|
to filter the report.
|
||||||
|
|
||||||
* " " (whitespace) indicates that all points on the line are above the coverage limit.
|
* " " (whitespace) indicates that all points on the line are above the coverage min.
|
||||||
* "%" indicates at least one point on the line was below the coverage limit.
|
* "%" indicates that all points on the line are below the coverage min.
|
||||||
* "+" coverage point was at or above the limit. Only used with :option:`--annotate-points`.
|
* "~" indicates that some points on the line are above the coverage min and some are below.
|
||||||
* "-" coverage point was below the limit. Only used with :option:`--annotate-points`.
|
* "+" 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::
|
.. code-block::
|
||||||
|
|
||||||
100000 input logic a; // Begins with whitespace, because
|
100000 input logic a; // Begins with whitespace, because
|
||||||
// number of hits (100000) is above the limit.
|
// number of hits (100000) is above the min.
|
||||||
+100000 point: comment=a // Begins with +, because
|
+100000 point: comment=a // Begins with +, because
|
||||||
// number of hits (100000) is above the limit.
|
// number of hits (100000) is above the min.
|
||||||
%000000 input logic b; // Begins with %, because
|
%000000 input logic b; // Begins with %, because
|
||||||
// number of hits (0) is below the limit.
|
// number of hits (0) is below the min.
|
||||||
-000000 point: comment=b // Begins with -, because
|
-000000 point: comment=b // Begins with -, because
|
||||||
// number of hits (0) is below the limit.
|
// 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
|
.. 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,
|
Specifies the aggregate coverage results, summed across all the files,
|
||||||
should be written to the given filename in :command:`lcov` .info format.
|
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
|
This may be used to feed into :command:`lcov` to aggregate or generate
|
||||||
reports.
|
reports. This format lacks the comments for cover points that the
|
||||||
|
verilator_coverage format has. It can be used with :command:`genhtml`
|
||||||
Converting from the Verilator coverage data format to the info format is
|
to generate an HTML report. :command:`genhtml --branch-coverage` will
|
||||||
lossy; the info will have all forms of coverage merged line coverage, and
|
also display the branch coverage, analogous to :option:`--annotate-points`
|
||||||
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.
|
|
||||||
|
|||||||
+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
|
Verilator creates standard VCD (Value Change Dump) and FST files. VCD
|
||||||
files are viewable with the open-source GTKWave (recommended), or Dinotrace
|
files are viewable with the open-source
|
||||||
(legacy) programs, or any of the many closed-source offerings; FST is
|
`GTKWave <http://gtkwave.sourceforge.net/>`_,
|
||||||
supported only by GTKWave.
|
`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?
|
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)
|
- Make include file for compiling (from --make gmake)
|
||||||
* - *{prefix}*\ _classes.mk
|
* - *{prefix}*\ _classes.mk
|
||||||
- Make include file with class names (from --make gmake)
|
- 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
|
* - *{prefix}*\ .h
|
||||||
- Model header
|
- Model header
|
||||||
* - *{prefix}*\ .cpp
|
* - *{prefix}*\ .cpp
|
||||||
@@ -95,16 +89,24 @@ For --cc/--sc, it creates:
|
|||||||
* - *{prefix}{each_verilog_module}{__DepSet_hash__n}*\ .cpp
|
* - *{prefix}{each_verilog_module}{__DepSet_hash__n}*\ .cpp
|
||||||
- Additional lower C++ files (hashed to reduce build times)
|
- Additional lower C++ files (hashed to reduce build times)
|
||||||
|
|
||||||
For --hierarchy mode, it creates:
|
For --hierarchical mode, it creates:
|
||||||
|
|
||||||
.. list-table::
|
.. list-table::
|
||||||
|
|
||||||
* - V\ *{hier_block}*\ /
|
* - V\ *{hier_block}*\ /
|
||||||
- Directory to Verilate each hierarchy block (from --hierarchy)
|
- Directory to Verilate each hierarchical block (from --hierarchical)
|
||||||
* - *{prefix}*\ __hierVer.d
|
* - *{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
|
* - *{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:
|
In specific debug and other modes, it also creates:
|
||||||
|
|
||||||
|
|||||||
+52
-21
@@ -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
|
:ref:`Git Install` might be a better alternative.) To install as a
|
||||||
package:
|
package:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
apt-get install verilator # On Ubuntu
|
apt-get install verilator # On Ubuntu
|
||||||
|
|
||||||
For other distributions, refer to `Repology Verilator Distro Packages
|
For other distributions, refer to `Repology Verilator Distro Packages
|
||||||
<https://repology.org/project/verilator>`__.
|
<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 Install:
|
||||||
|
|
||||||
Git Quick Install
|
Git Quick Install
|
||||||
@@ -36,7 +56,7 @@ options and details, see :ref:`Detailed Build Instructions` below.
|
|||||||
|
|
||||||
In brief, to install from git:
|
In brief, to install from git:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
# Prerequisites:
|
# Prerequisites:
|
||||||
#sudo apt-get install git help2man perl python3 make autoconf g++ flex bison ccache
|
#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:
|
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 git help2man perl python3 make
|
||||||
sudo apt-get install g++ # Alternatively, clang
|
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
|
To build or run Verilator, the following are optional but should be installed
|
||||||
for good performance:
|
for good performance:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
sudo apt-get install ccache # If present at build, needed for run
|
sudo apt-get install ccache # If present at build, needed for run
|
||||||
sudo apt-get install mold # 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
|
The following is optional but is recommended for nicely rendered command line
|
||||||
help when running Verilator:
|
help when running Verilator:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
sudo apt-get install perl-doc
|
sudo apt-get install perl-doc
|
||||||
|
|
||||||
To build Verilator you will need to install these packages; these do not
|
To build Verilator you will need to install these packages; these do not
|
||||||
need to be present to run Verilator:
|
need to be present to run Verilator:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
sudo apt-get install git autoconf flex bison
|
sudo apt-get install git autoconf flex bison
|
||||||
|
|
||||||
Those developing Verilator itself may also want these (see internals.rst):
|
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 clang clang-format-14 cmake gdb gprof graphviz lcov
|
||||||
sudo apt-get install python3-clang yapf3 bear jq
|
sudo apt-get install python3-clang yapf3 bear jq
|
||||||
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe ruff
|
||||||
sudo pip3 install git+https://github.com/antmicro/astsee.git
|
sudo pip3 install git+https://github.com/antmicro/astsee.git
|
||||||
cpan install Pod::Perldoc
|
cpan install Pod::Perldoc
|
||||||
cpan install Parallel::Forker
|
|
||||||
|
|
||||||
|
|
||||||
Install SystemC
|
Install SystemC
|
||||||
@@ -152,6 +171,17 @@ To make use of Verilator FST tracing you will want `GTKwave
|
|||||||
required at Verilator build time.
|
required at Verilator build time.
|
||||||
|
|
||||||
|
|
||||||
|
Install Z3
|
||||||
|
^^^^^^^^^^
|
||||||
|
|
||||||
|
In order to use constrained randomization the `Z3 Theorem Prover
|
||||||
|
<https://github.com/z3prover/z3#readme>`__ must be installed, however this is
|
||||||
|
not required at Verilator build time. There are other compatible SMT solvers,
|
||||||
|
like CVC5/CVC4, but they are not guaranteed to work. Since different solvers are
|
||||||
|
faster for different scenarios, the solver to use at run-time can be specified
|
||||||
|
by the environment variable :option:`VERILATOR_SOLVER`.
|
||||||
|
|
||||||
|
|
||||||
.. _Obtain Sources:
|
.. _Obtain Sources:
|
||||||
|
|
||||||
Obtain Sources
|
Obtain Sources
|
||||||
@@ -160,14 +190,14 @@ Obtain Sources
|
|||||||
Get the sources from the git repository: (You need to do this only once,
|
Get the sources from the git repository: (You need to do this only once,
|
||||||
ever.)
|
ever.)
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
git clone https://github.com/verilator/verilator # Only first time
|
git clone https://github.com/verilator/verilator # Only first time
|
||||||
## Note the URL above is not a page you can see with a browser; it's for git only
|
## Note the URL above is not a page you can see with a browser; it's for git only
|
||||||
|
|
||||||
Enter the checkout and determine what version/branch to use:
|
Enter the checkout and determine what version/branch to use:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
cd verilator
|
cd verilator
|
||||||
git pull # Make sure we're up-to-date
|
git pull # Make sure we're up-to-date
|
||||||
@@ -182,7 +212,7 @@ Auto Configure
|
|||||||
|
|
||||||
Create the configuration script:
|
Create the configuration script:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
autoconf # Create ./configure script
|
autoconf # Create ./configure script
|
||||||
|
|
||||||
@@ -193,8 +223,9 @@ Eventual Installation Options
|
|||||||
Before configuring the build, you must decide how you're going to
|
Before configuring the build, you must decide how you're going to
|
||||||
eventually install Verilator onto your system. Verilator will be compiling
|
eventually install Verilator onto your system. Verilator will be compiling
|
||||||
the current value of the environment variables :option:`VERILATOR_ROOT`,
|
the current value of the environment variables :option:`VERILATOR_ROOT`,
|
||||||
:option:`SYSTEMC_INCLUDE`, and :option:`SYSTEMC_LIBDIR` as defaults into
|
:option:`VERILATOR_SOLVER`, :option:`SYSTEMC_INCLUDE`, and
|
||||||
the executable, so they must be correct before configuring.
|
:option:`SYSTEMC_LIBDIR` as defaults into the executable, so they must be
|
||||||
|
correct before configuring.
|
||||||
|
|
||||||
These are the installation options:
|
These are the installation options:
|
||||||
|
|
||||||
@@ -207,7 +238,7 @@ directory (don't run ``make install``). This allows the easiest
|
|||||||
experimentation and upgrading, and allows many versions of Verilator to
|
experimentation and upgrading, and allows many versions of Verilator to
|
||||||
co-exist on a system.
|
co-exist on a system.
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
export VERILATOR_ROOT=`pwd` # if your shell is bash
|
export VERILATOR_ROOT=`pwd` # if your shell is bash
|
||||||
setenv VERILATOR_ROOT `pwd` # if your shell is csh
|
setenv VERILATOR_ROOT `pwd` # if your shell is csh
|
||||||
@@ -229,7 +260,7 @@ that may support multiple versions of every tool. Tell configure the
|
|||||||
eventual destination directory name. We recommend that the destination
|
eventual destination directory name. We recommend that the destination
|
||||||
location include the Verilator version name:
|
location include the Verilator version name:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
unset VERILATOR_ROOT # if your shell is bash
|
unset VERILATOR_ROOT # if your shell is bash
|
||||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||||
@@ -241,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
|
<http://modules.sourceforge.net/>`__, you'll want a module file like the
|
||||||
following:
|
following:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
set install_root /CAD_DISK/verilator/{version-number-used-above}
|
set install_root /CAD_DISK/verilator/{version-number-used-above}
|
||||||
unsetenv VERILATOR_ROOT
|
unsetenv VERILATOR_ROOT
|
||||||
@@ -256,7 +287,7 @@ following:
|
|||||||
The final option is to eventually install Verilator globally, using
|
The final option is to eventually install Verilator globally, using
|
||||||
configure's default system paths:
|
configure's default system paths:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
unset VERILATOR_ROOT # if your shell is bash
|
unset VERILATOR_ROOT # if your shell is bash
|
||||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||||
@@ -273,7 +304,7 @@ The command to configure the package was described in the previous step.
|
|||||||
Developers should configure to have more complete developer tests.
|
Developers should configure to have more complete developer tests.
|
||||||
Additional packages may be required for these tests.
|
Additional packages may be required for these tests.
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
export VERILATOR_AUTHOR_SITE=1 # Put in your .bashrc
|
export VERILATOR_AUTHOR_SITE=1 # Put in your .bashrc
|
||||||
./configure --enable-longtests ...above options...
|
./configure --enable-longtests ...above options...
|
||||||
@@ -284,7 +315,7 @@ Compile
|
|||||||
|
|
||||||
Compile Verilator:
|
Compile Verilator:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
make -j `nproc` # Or if error on `nproc`, the number of CPUs in system
|
make -j `nproc` # Or if error on `nproc`, the number of CPUs in system
|
||||||
|
|
||||||
@@ -294,7 +325,7 @@ Test
|
|||||||
|
|
||||||
Check the compilation by running self-tests:
|
Check the compilation by running self-tests:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
make test
|
make test
|
||||||
|
|
||||||
@@ -306,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
|
VERILATOR_ROOT <#_1_run_in_place_from_verilator_root>`__ scheme, install
|
||||||
the files:
|
the files:
|
||||||
|
|
||||||
::
|
.. code-block:: shell
|
||||||
|
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ Simulation Summary Report
|
|||||||
=========================
|
=========================
|
||||||
|
|
||||||
When simulation finishes, it will print a report to stdout summarizing the
|
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`.
|
The report may be disabled with :vlopt:`+verilator+quiet`.
|
||||||
|
|
||||||
For example:
|
For example:
|
||||||
|
|||||||
@@ -304,9 +304,9 @@ GNU Make
|
|||||||
========
|
========
|
||||||
|
|
||||||
Verilator defaults to creating GNU Make makefiles for the model. Verilator
|
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
|
a dependency file, allowing Make to only run Verilator if input Verilog
|
||||||
files change.
|
files change.
|
||||||
|
|
||||||
|
|||||||
+88
-32
@@ -210,22 +210,35 @@ List Of Warnings
|
|||||||
|
|
||||||
.. option:: BLKLOOPINIT
|
.. option:: BLKLOOPINIT
|
||||||
|
|
||||||
.. TODO better example
|
Indicates certain constructs where non-blocking assignments to unpacked
|
||||||
|
arrays (memories) are not supported inside loops. These typically appear in
|
||||||
This indicates that the initialization of an array needs to use
|
initialization/reset code:
|
||||||
non-delayed assignments. This is done in the interest of speed; if
|
|
||||||
delayed assignments were used, the simulator would have to copy large
|
|
||||||
arrays every cycle. (In smaller loops, loop unrolling allows the
|
|
||||||
delayed assignment to work, though it's a bit slower than a non-delayed
|
|
||||||
assignment.) Here's an example
|
|
||||||
|
|
||||||
.. code-block:: sv
|
.. code-block:: sv
|
||||||
|
|
||||||
always @(posedge clk)
|
always @(posedge clk)
|
||||||
if (~reset_l)
|
if (~reset_l)
|
||||||
for (i=0; i<`ARRAY_SIZE; i++)
|
for (i=0; i<`ARRAY_SIZE; i++)
|
||||||
array[i] = 0; // Non-delayed for verilator
|
array[i] <= 0; // Non-blocking assignment inside loop
|
||||||
|
else
|
||||||
|
array[address] <= data;
|
||||||
|
|
||||||
|
While this is supported in typical synthesizeable code (including the
|
||||||
|
example above), some complicated cases are not supported. Namely:
|
||||||
|
|
||||||
|
1. If the above loop is inside a suspendable process or fork statement.
|
||||||
|
|
||||||
|
2. If the variable is also the target of a '<=' non-blocking assignment
|
||||||
|
in a suspendable process or fork statement (in addition to a synthesizable
|
||||||
|
loop).
|
||||||
|
|
||||||
|
3. If the element type of the array is a compound type.
|
||||||
|
|
||||||
|
4. In versions before 5.026, any delayed assignment to an array.
|
||||||
|
|
||||||
|
It might slightly improve run-time performance if you change the
|
||||||
|
non-blocking assignment inside the loop into a blocking assignment
|
||||||
|
(that is: use '=' instead of '<='), if possible.
|
||||||
|
|
||||||
This message is only seen on large or complicated loops because
|
This message is only seen on large or complicated loops because
|
||||||
Verilator generally unrolls small loops. You may want to try increasing
|
Verilator generally unrolls small loops. You may want to try increasing
|
||||||
@@ -406,9 +419,9 @@ List Of Warnings
|
|||||||
|
|
||||||
.. option:: CONSTRAINTIGN
|
.. option:: CONSTRAINTIGN
|
||||||
|
|
||||||
Warns that Verilator does not support :code:`constraint`,
|
Warns that Verilator does not support certain forms of
|
||||||
:code:`constraint_mode`, or :code:`rand_mode`, and the construct was are
|
:code:`constraint`, :code:`constraint_mode`, or :code:`rand_mode`, and
|
||||||
ignored.
|
the construct was are ignored.
|
||||||
|
|
||||||
Ignoring this warning may make Verilator randomize() simulations differ
|
Ignoring this warning may make Verilator randomize() simulations differ
|
||||||
from other simulators.
|
from other simulators.
|
||||||
@@ -1204,6 +1217,14 @@ List Of Warnings
|
|||||||
:vlopt:`--no-timing` option.
|
:vlopt:`--no-timing` option.
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: NONSTD
|
||||||
|
|
||||||
|
Warns when a non-standard language feature is used that has a standard
|
||||||
|
equivalent, which might behave differently in corner cases. For example
|
||||||
|
:code:`$psprintf` system function is replaced by its standard equivalent
|
||||||
|
:code:`$sformatf`.
|
||||||
|
|
||||||
|
|
||||||
.. option:: NULLPORT
|
.. option:: NULLPORT
|
||||||
|
|
||||||
Warns that a null port was detected in the module definition port
|
Warns that a null port was detected in the module definition port
|
||||||
@@ -1243,7 +1264,7 @@ List Of Warnings
|
|||||||
|
|
||||||
.. option:: PINMISSING
|
.. option:: PINMISSING
|
||||||
|
|
||||||
.. TODO better example
|
.. TODO better example (frequent)
|
||||||
|
|
||||||
Warns that a module has a pin that is not mentioned in an instance. If
|
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
|
a pin is not missing it should still be specified on the instance
|
||||||
@@ -1252,6 +1273,22 @@ List Of Warnings
|
|||||||
Ignoring this warning will only suppress the lint check; it will
|
Ignoring this warning will only suppress the lint check; it will
|
||||||
simulate correctly.
|
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:
|
Other tools with similar warnings: Icarus Verilog's portbind, "warning:
|
||||||
Instantiating module ... with dangling input port (...)". Slang's
|
Instantiating module ... with dangling input port (...)". Slang's
|
||||||
unconnected-port, "port '...' has no connection".
|
unconnected-port, "port '...' has no connection".
|
||||||
@@ -1283,7 +1320,7 @@ List Of Warnings
|
|||||||
generate
|
generate
|
||||||
if (A==0) begin
|
if (A==0) begin
|
||||||
b b_inst1 (.x(1'b0)); //<--- error nonexistent port
|
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
|
end
|
||||||
endgenerate
|
endgenerate
|
||||||
endmodule
|
endmodule
|
||||||
@@ -1325,11 +1362,22 @@ List Of Warnings
|
|||||||
|
|
||||||
.. option:: PKGNODECL
|
.. 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
|
Faulty example:
|
||||||
yet been declared. According to IEEE 1800-2023 26.3, all packages must
|
|
||||||
be declared before being used.
|
.. 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
|
.. option:: PREPROCZERO
|
||||||
@@ -1354,7 +1402,7 @@ List Of Warnings
|
|||||||
`endif
|
`endif
|
||||||
|
|
||||||
The portable way to suppress this warning is to use a define value other
|
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
|
.. option:: PROCASSWIRE
|
||||||
@@ -1876,7 +1924,8 @@ List Of Warnings
|
|||||||
|
|
||||||
.. option:: UNPACKED
|
.. 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,
|
Ignoring this warning will make Verilator treat the structure as packed,
|
||||||
which may make Verilator simulations differ from other simulators. This
|
which may make Verilator simulations differ from other simulators. This
|
||||||
@@ -1927,14 +1976,16 @@ List Of Warnings
|
|||||||
|
|
||||||
.. TODO better example
|
.. 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
|
.. option:: UNUSEDPARAM
|
||||||
|
|
||||||
.. TODO better example
|
.. 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
|
.. option:: UNUSEDSIGNAL
|
||||||
@@ -2057,10 +2108,6 @@ List Of Warnings
|
|||||||
|
|
||||||
.. option:: WAITCONST
|
.. option:: WAITCONST
|
||||||
|
|
||||||
.. code-block:: sv
|
|
||||||
|
|
||||||
wait(1); // Blocks forever
|
|
||||||
|
|
||||||
Warns that a `wait` statement awaits a constant condition, which means it
|
Warns that a `wait` statement awaits a constant condition, which means it
|
||||||
either blocks forever or never blocks.
|
either blocks forever or never blocks.
|
||||||
|
|
||||||
@@ -2068,6 +2115,12 @@ List Of Warnings
|
|||||||
something that elaborates to zero), does not warn, as it is presumed the
|
something that elaborates to zero), does not warn, as it is presumed the
|
||||||
code is making the intent clear.
|
code is making the intent clear.
|
||||||
|
|
||||||
|
Faulty example:
|
||||||
|
|
||||||
|
.. code-block:: sv
|
||||||
|
|
||||||
|
wait(1); // Blocks forever
|
||||||
|
|
||||||
|
|
||||||
.. option:: WIDTH
|
.. option:: WIDTH
|
||||||
|
|
||||||
@@ -2104,7 +2157,7 @@ List Of Warnings
|
|||||||
|
|
||||||
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_faulty.rst
|
.. 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
|
.. include:: ../../docs/gen/ex_WIDTHEXPAND_1_msg.rst
|
||||||
|
|
||||||
@@ -2115,15 +2168,18 @@ List Of Warnings
|
|||||||
|
|
||||||
.. option:: WIDTHTRUNC
|
.. 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
|
.. 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
|
.. 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
|
.. option:: WIDTHCONCAT
|
||||||
|
|
||||||
@@ -2172,7 +2228,7 @@ List Of Warnings
|
|||||||
#(parameter int MY_PARAM = 0);
|
#(parameter int MY_PARAM = 0);
|
||||||
reg [7:0] data;
|
reg [7:0] data;
|
||||||
always @* begin
|
always @* begin
|
||||||
data = {MY_PARAM{1'b1}}; //<--- WARNING
|
data = {MY_PARAM{1'b1}}; //<--- Warning
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
@@ -2193,7 +2249,7 @@ List Of Warnings
|
|||||||
:emphasize-lines: 2
|
:emphasize-lines: 2
|
||||||
|
|
||||||
module dut
|
module dut
|
||||||
#(parameter int MY_PARAM = 1); //<--- REPAIRED
|
#(parameter int MY_PARAM = 1); //<--- REPAIRED
|
||||||
reg [7:0] data;
|
reg [7:0] data;
|
||||||
always @* begin
|
always @* begin
|
||||||
data = {MY_PARAM{1'b1}};
|
data = {MY_PARAM{1'b1}};
|
||||||
|
|||||||
+126
-54
@@ -1031,6 +1031,91 @@ the evaluation process records a bitmask of variables that might have
|
|||||||
changed; if clear, checking those signals for changes may be skipped.
|
changed; if clear, checking those signals for changes may be skipped.
|
||||||
|
|
||||||
|
|
||||||
|
Constrained randomization
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Because general constrained randomization is a co-NP-hard problem, not all
|
||||||
|
cases are implemented in Verilator, and an external specialized SMT solver is
|
||||||
|
used for any non-obvious ones.
|
||||||
|
|
||||||
|
The ``randomize()`` method spawns an SMT solver in a sub-process. Then the
|
||||||
|
solver gets a setup query, then the definition of variables, then all the
|
||||||
|
constraints (SMT assertions) about the variables. Since the solver has no
|
||||||
|
information about the class' PRNG state, if the problem is satisfiable,
|
||||||
|
the solution space is further constrained by adding extra random constraints,
|
||||||
|
and querying the values satisfying the problem statement.
|
||||||
|
The constraint is currently constructed as fixing a simple xor of randomly
|
||||||
|
chosen bits of the variables being randomized.
|
||||||
|
|
||||||
|
The runtime classes used for handling the randomization are defined in
|
||||||
|
``verilated_random.h`` and ``verilated_random.cpp``.
|
||||||
|
|
||||||
|
|
||||||
|
``VlSubprocess``
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Subprocess handle, responsible for keeping track of the resources like child
|
||||||
|
PID, read and write file descriptors, and presenting them as a C++ iostream.
|
||||||
|
|
||||||
|
|
||||||
|
``VlRandomizer``
|
||||||
|
~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Randomizer class, responsible for keeping track of variables and constraints,
|
||||||
|
and communicating with the solver subprocess.
|
||||||
|
|
||||||
|
The solver gets the constraints in `SMT-LIB2
|
||||||
|
<https://smtlib.cs.uiowa.edu/>`__ textual format in the following syntax:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
(set-info :smt-lib-version 2.0)
|
||||||
|
(set-option :produce-models true)
|
||||||
|
(set-logic QF_BV)
|
||||||
|
|
||||||
|
(declare-fun v () (_ BitVec 16))
|
||||||
|
(declare-fun w () (_ BitVec 64))
|
||||||
|
(declare-fun x () (_ BitVec 48))
|
||||||
|
(declare-fun z () (_ BitVec 24))
|
||||||
|
(declare-fun t () (_ BitVec 23))
|
||||||
|
(assert (or (= v #x0003) (= v #x0008)))
|
||||||
|
(assert (= w #x0000000000000009))
|
||||||
|
(assert (or (or (= x #x000000000001) (= x #x000000000002)) (or (= x #x000000000004) (= x #x000000000009))))
|
||||||
|
(assert (bvult ((_ zero_extend 8) z) #x00000015))
|
||||||
|
(assert (bvugt ((_ zero_extend 8) z) #x0000000d))
|
||||||
|
|
||||||
|
(check-sat)
|
||||||
|
|
||||||
|
The solver responds with either ``sat`` or ``unsat``. Then the initial solution
|
||||||
|
is queried with:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
(get-value (v w x z t ))
|
||||||
|
|
||||||
|
The solver then responds with e.g.:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
((v #x0008)
|
||||||
|
(w #x0000000000000005)
|
||||||
|
(x #x000000000002)
|
||||||
|
(z #x000010)
|
||||||
|
(t #b00000000000000000000000))
|
||||||
|
|
||||||
|
And then a follow-up query (or a series thereof) is asked, and the solver gets
|
||||||
|
reset, so that it can be reused by subsequent randomization attempts:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
(assert (= (bvxor (bvxor <...> (bvxor ((_ extract 21 21) z) ((_ extract 39 39) x)) ((_ extract 5 5) w)) <...> ((_ extract 10 10) w)) #b0))
|
||||||
|
(check-sat)
|
||||||
|
(get-value)
|
||||||
|
...
|
||||||
|
(reset)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Coding Conventions
|
Coding Conventions
|
||||||
==================
|
==================
|
||||||
|
|
||||||
@@ -1387,9 +1472,6 @@ For all tests to pass, you must install the following packages:
|
|||||||
|
|
||||||
- SystemC to compile the SystemC outputs, see http://systemc.org
|
- 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
|
- vcddiff to find differences in VCD outputs. See the readme at
|
||||||
https://github.com/veripool/vcddiff
|
https://github.com/veripool/vcddiff
|
||||||
|
|
||||||
@@ -1399,7 +1481,7 @@ For all tests to pass, you must install the following packages:
|
|||||||
Controlling the Test Driver
|
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
|
section. The individual test drivers are written in Perl; see `Test
|
||||||
Language`.
|
Language`.
|
||||||
|
|
||||||
@@ -1412,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
|
Regression Testing for Developers
|
||||||
@@ -1432,13 +1514,6 @@ Developers will also want to call ./configure with two extra flags:
|
|||||||
disabled by default, as SystemC installation problems would otherwise
|
disabled by default, as SystemC installation problems would otherwise
|
||||||
falsely indicate a Verilator problem.
|
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
|
There are some traps to avoid when running regression tests
|
||||||
|
|
||||||
- When checking the MANIFEST, the test will fail on unexpected code in the
|
- When checking the MANIFEST, the test will fail on unexpected code in the
|
||||||
@@ -1786,7 +1861,7 @@ represent the pointers (``op1p``, ``op2p``, etc) between the nodes.
|
|||||||
Debugging with GDB
|
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
|
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
|
to exit. You can also use ``--debug --gdbbt`` to just backtrace and then
|
||||||
exit gdb. To debug the Verilated executable, use ``--gdbsim``.
|
exit gdb. To debug the Verilated executable, use ``--gdbsim``.
|
||||||
@@ -1797,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:
|
shows it invokes the command:
|
||||||
|
|
||||||
@@ -1894,7 +1969,7 @@ Generally, what would you do to add a new feature?
|
|||||||
Follow the convention described above about the AstNode type hierarchy.
|
Follow the convention described above about the AstNode type hierarchy.
|
||||||
Ordering of definitions is enforced by ``astgen``.
|
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
|
probably fail, but you'll see a
|
||||||
``test_regress/obj_dir/t_<newtestcase>/*.tree`` file which you can examine
|
``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.
|
to see if the parsing worked. See also the sections above on debugging.
|
||||||
@@ -1943,7 +2018,7 @@ IEEE 1800-2023 33 Config
|
|||||||
Test Driver
|
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
|
invokes Verilator or another simulator on each test file. For test file
|
||||||
contents description see `Test Language`.
|
contents description see `Test Language`.
|
||||||
|
|
||||||
@@ -1955,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.
|
with many cores. See the -j option and OBJCACHE environment variable.
|
||||||
|
|
||||||
|
|
||||||
driver.pl Non-Scenario Arguments
|
driver.py Non-Scenario Arguments
|
||||||
--------------------------------
|
--------------------------------
|
||||||
|
|
||||||
--benchmark [<cycles>]
|
--benchmark [<cycles>]
|
||||||
@@ -2025,13 +2100,13 @@ driver.pl Non-Scenario Arguments
|
|||||||
memory leaks.
|
memory leaks.
|
||||||
|
|
||||||
--site
|
--site
|
||||||
Run site specific tests also.
|
Run site-specific tests also.
|
||||||
|
|
||||||
--stop
|
--stop
|
||||||
Stop on the first error.
|
Stop on the first error.
|
||||||
|
|
||||||
--trace
|
--trace
|
||||||
Set the simulator specific flags to request waveform tracing.
|
Set the simulator-specific flags to request waveform tracing.
|
||||||
|
|
||||||
--valgrind
|
--valgrind
|
||||||
Same as ``verilator --valgrind``: Run Verilator under `Valgrind <https://valgrind.org/>`_.
|
Same as ``verilator --valgrind``: Run Verilator under `Valgrind <https://valgrind.org/>`_.
|
||||||
@@ -2044,7 +2119,7 @@ driver.pl Non-Scenario Arguments
|
|||||||
For tests using the standard C++ wrapper, enable runtime debug mode.
|
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
|
The following options control which simulator is used, and which tests are
|
||||||
@@ -2086,7 +2161,7 @@ simultaneously.
|
|||||||
Run Xilinx XSim simulator tests.
|
Run Xilinx XSim simulator tests.
|
||||||
|
|
||||||
|
|
||||||
driver.pl Environment
|
driver.py Environment
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
HARNESS_UPDATE_GOLDEN
|
HARNESS_UPDATE_GOLDEN
|
||||||
@@ -2125,6 +2200,10 @@ VERILATOR_ROOT
|
|||||||
Standard path to Verilator distribution root; see primary Verilator
|
Standard path to Verilator distribution root; see primary Verilator
|
||||||
documentation.
|
documentation.
|
||||||
|
|
||||||
|
VERILATOR_SOLVER
|
||||||
|
SMT solver command for constrained randomization; see primary Verilator
|
||||||
|
documentation.
|
||||||
|
|
||||||
VERILATOR_TESTS_SITE
|
VERILATOR_TESTS_SITE
|
||||||
Used with ``--site``, a colon-separated list of directories with tests to
|
Used with ``--site``, a colon-separated list of directories with tests to
|
||||||
be added to testlist.
|
be added to testlist.
|
||||||
@@ -2142,30 +2221,30 @@ VERILATOR_XVLOG
|
|||||||
Test Language
|
Test Language
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This section describes the format of the ``test_regress/t/*.pl`` test
|
This section describes the format of the ``test_regress/t/*.py`` test
|
||||||
language files, executed by `driver.pl`.
|
language files, executed by `driver.py`.
|
||||||
|
|
||||||
Test Language Summary
|
Test Language Summary
|
||||||
---------------------
|
---------------------
|
||||||
|
|
||||||
For convenience, a summary of the most commonly used features is provided
|
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
|
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
|
call to the ``test.lint`` or ``test.compile`` methods to compile the
|
||||||
run-time tests, this is followed by a call to the ``execute``
|
test. For run-time tests, this is followed by a call to the
|
||||||
subroutine. Both of these functions can optionally be provided with
|
``test.execute`` method. Both of these functions can optionally be provided
|
||||||
arguments specifying additional options.
|
with arguments specifying additional options.
|
||||||
|
|
||||||
If those complete, the script calls ``ok`` to increment the count of
|
If those complete, the script calls ``test.passes`` to increment the count
|
||||||
successful tests and then returns 1 as its result.
|
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
|
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
|
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,
|
By default, all tests will run with major simulators (Icarus Verilog, NC,
|
||||||
VCS, ModelSim, etc.) as well as Verilator, to allow results to be
|
VCS, ModelSim, etc.) as well as Verilator, to allow results to be
|
||||||
@@ -2174,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
|
Of the many options that can be set through arguments to ``test.compiler``
|
||||||
``execute``, the following are particularly useful:
|
and ``test.execute``, the following are particularly useful:
|
||||||
|
|
||||||
``verilator_flags2``
|
``verilator_flags2``
|
||||||
A list of flags to be passed to verilator when compiling.
|
A list of flags to be passed to verilator when compiling.
|
||||||
|
|
||||||
``fails``
|
``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
|
For example, the following would specify that compilation requires two
|
||||||
defines and is expected to fail.
|
defines and is expected to fail.
|
||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
compile(
|
test.compile(
|
||||||
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
|
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
|
||||||
fails => 1,
|
fails = True)
|
||||||
);
|
|
||||||
|
|
||||||
Hints On Writing Tests
|
Hints On Writing Tests
|
||||||
----------------------
|
----------------------
|
||||||
@@ -2206,10 +2284,10 @@ same name as the test, but with .cpp as suffix
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
compile(
|
test.compile(
|
||||||
make_top_shell => 0,
|
make_top_shell=False,
|
||||||
make_main => 0,
|
make_main=False,
|
||||||
verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], );
|
verilator_flags2=["--exe", test.t_dir + "/" + test.name + ".cpp"])
|
||||||
|
|
||||||
Tests should be self-checking, rather than producing lots of output. If a
|
Tests should be self-checking, rather than producing lots of output. If a
|
||||||
test succeeds it should print ``*-* All Finished *-*`` to standard output
|
test succeeds it should print ``*-* All Finished *-*`` to standard output
|
||||||
@@ -2249,9 +2327,8 @@ compile time, it is the only option. For example:
|
|||||||
::
|
::
|
||||||
|
|
||||||
compile(
|
compile(
|
||||||
fails => 1,
|
fails=True,
|
||||||
expect_filename => $Self->{golden_filename},
|
expect_filename=test.golden_filename)
|
||||||
);
|
|
||||||
|
|
||||||
Note ``expect_filename`` strips some debugging information from the logfile
|
Note ``expect_filename`` strips some debugging information from the logfile
|
||||||
when comparing.
|
when comparing.
|
||||||
@@ -2260,9 +2337,9 @@ when comparing.
|
|||||||
Test Language Compile/Lint/Run Arguments
|
Test Language Compile/Lint/Run Arguments
|
||||||
----------------------------------------
|
----------------------------------------
|
||||||
|
|
||||||
This section describes common arguments to ``compile()``, ``lint()``, and
|
This section describes common arguments to ``test.compile``, ``test.lint``,
|
||||||
``run()``. The full list of arguments can be found by looking at the
|
and ``test.run``. The full list of arguments can be found by looking at
|
||||||
``driver.pl`` source code.
|
the ``driver.py`` source code.
|
||||||
|
|
||||||
all_run_flags
|
all_run_flags
|
||||||
A list of flags to be passed when running the simulator (Verilated model
|
A list of flags to be passed when running the simulator (Verilated model
|
||||||
@@ -2273,11 +2350,6 @@ check_finished
|
|||||||
string ``*-* All Finished *-*`` being printed on standard output. This is
|
string ``*-* All Finished *-*`` being printed on standard output. This is
|
||||||
the normal way for successful tests to finish.
|
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
|
fails
|
||||||
True to indicate this step is expected to fail. Tests that are expected
|
True to indicate this step is expected to fail. Tests that are expected
|
||||||
to fail generally have _bad in their filename.
|
to fail generally have _bad in their filename.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ Ashutosh
|
|||||||
Ast
|
Ast
|
||||||
Atmel
|
Atmel
|
||||||
Aurelien
|
Aurelien
|
||||||
|
Badáň
|
||||||
Bagri
|
Bagri
|
||||||
Balboni
|
Balboni
|
||||||
Baltazar
|
Baltazar
|
||||||
@@ -40,6 +41,7 @@ Brej
|
|||||||
Briquet
|
Briquet
|
||||||
Brownlee
|
Brownlee
|
||||||
Buckenmaier
|
Buckenmaier
|
||||||
|
Burghoorn
|
||||||
Bybell
|
Bybell
|
||||||
CLang
|
CLang
|
||||||
CMake
|
CMake
|
||||||
@@ -73,6 +75,7 @@ Deepa
|
|||||||
Defparams
|
Defparams
|
||||||
Delm
|
Delm
|
||||||
Denio
|
Denio
|
||||||
|
Deniz
|
||||||
Deprecations
|
Deprecations
|
||||||
Deroo
|
Deroo
|
||||||
Desai
|
Desai
|
||||||
@@ -108,8 +111,10 @@ Eugen
|
|||||||
Fabrizio
|
Fabrizio
|
||||||
Faucher
|
Faucher
|
||||||
Faure
|
Faure
|
||||||
|
Feinberg
|
||||||
Fekete
|
Fekete
|
||||||
Ferrandi
|
Ferrandi
|
||||||
|
Filip
|
||||||
Flachs
|
Flachs
|
||||||
Flavien
|
Flavien
|
||||||
Florian
|
Florian
|
||||||
@@ -131,6 +136,7 @@ Gernot
|
|||||||
Gerst
|
Gerst
|
||||||
Gielda
|
Gielda
|
||||||
Gigerl
|
Gigerl
|
||||||
|
Gijs
|
||||||
Gileadi
|
Gileadi
|
||||||
Giri
|
Giri
|
||||||
Gisselquist
|
Gisselquist
|
||||||
@@ -147,6 +153,7 @@ Grulfen
|
|||||||
Gu
|
Gu
|
||||||
Gunter
|
Gunter
|
||||||
Guo
|
Guo
|
||||||
|
Güzel
|
||||||
Hameed
|
Hameed
|
||||||
Hao
|
Hao
|
||||||
Haojin
|
Haojin
|
||||||
@@ -164,6 +171,7 @@ Homebrew
|
|||||||
Hornung
|
Hornung
|
||||||
Hossell
|
Hossell
|
||||||
Hsu
|
Hsu
|
||||||
|
Huggett
|
||||||
Hutt
|
Hutt
|
||||||
Hyperthreading
|
Hyperthreading
|
||||||
Ibrahim
|
Ibrahim
|
||||||
@@ -240,6 +248,7 @@ Liwei
|
|||||||
Lockhart
|
Lockhart
|
||||||
Longo
|
Longo
|
||||||
Luca
|
Luca
|
||||||
|
Luiza
|
||||||
Lussier
|
Lussier
|
||||||
Lübeck
|
Lübeck
|
||||||
MMD
|
MMD
|
||||||
@@ -270,6 +279,8 @@ MinW
|
|||||||
Mindspeed
|
Mindspeed
|
||||||
MingW
|
MingW
|
||||||
Miodrag
|
Miodrag
|
||||||
|
Moberg
|
||||||
|
Mobert
|
||||||
ModelSim
|
ModelSim
|
||||||
Modport
|
Modport
|
||||||
Moinak
|
Moinak
|
||||||
@@ -351,6 +362,7 @@ Sasselli
|
|||||||
Scharrer
|
Scharrer
|
||||||
Seitz
|
Seitz
|
||||||
Shahid
|
Shahid
|
||||||
|
Shahrestani
|
||||||
Shankar
|
Shankar
|
||||||
Shanshan
|
Shanshan
|
||||||
Sharad
|
Sharad
|
||||||
@@ -361,6 +373,7 @@ Shi
|
|||||||
Shinkarovsky
|
Shinkarovsky
|
||||||
Shinya
|
Shinya
|
||||||
Shirakawa
|
Shirakawa
|
||||||
|
Shou
|
||||||
Shuba
|
Shuba
|
||||||
Shunyao
|
Shunyao
|
||||||
Slager
|
Slager
|
||||||
@@ -372,10 +385,12 @@ Solaris
|
|||||||
Solomatnikov
|
Solomatnikov
|
||||||
Solt
|
Solt
|
||||||
Southwell
|
Southwell
|
||||||
|
Spack
|
||||||
Srini
|
Srini
|
||||||
Srinivasan
|
Srinivasan
|
||||||
Stamness
|
Stamness
|
||||||
Stephane
|
Stephane
|
||||||
|
Sterin
|
||||||
Stoddard
|
Stoddard
|
||||||
Stroebel
|
Stroebel
|
||||||
Strouble
|
Strouble
|
||||||
@@ -458,6 +473,7 @@ Wojciech
|
|||||||
Wolfel
|
Wolfel
|
||||||
Wouters
|
Wouters
|
||||||
Wpedantic
|
Wpedantic
|
||||||
|
Wunused
|
||||||
Wwarn
|
Wwarn
|
||||||
XSim
|
XSim
|
||||||
Xcelium
|
Xcelium
|
||||||
@@ -494,6 +510,7 @@ architected
|
|||||||
args
|
args
|
||||||
arrarys
|
arrarys
|
||||||
assertOn
|
assertOn
|
||||||
|
assertcontrol
|
||||||
astgen
|
astgen
|
||||||
async
|
async
|
||||||
atClone
|
atClone
|
||||||
@@ -510,6 +527,7 @@ basename
|
|||||||
bbox
|
bbox
|
||||||
benchmarking
|
benchmarking
|
||||||
biguint
|
biguint
|
||||||
|
bindir
|
||||||
biops
|
biops
|
||||||
bisonpre
|
bisonpre
|
||||||
bitOpTree
|
bitOpTree
|
||||||
@@ -579,6 +597,7 @@ datadir
|
|||||||
datafiles
|
datafiles
|
||||||
david
|
david
|
||||||
ddd
|
ddd
|
||||||
|
de
|
||||||
deassign
|
deassign
|
||||||
debugi
|
debugi
|
||||||
defenv
|
defenv
|
||||||
@@ -586,6 +605,7 @@ defname
|
|||||||
defparam
|
defparam
|
||||||
demangling
|
demangling
|
||||||
dep
|
dep
|
||||||
|
deparametrized
|
||||||
der
|
der
|
||||||
dereference
|
dereference
|
||||||
desassign
|
desassign
|
||||||
@@ -698,6 +718,7 @@ genvar
|
|||||||
genvars
|
genvars
|
||||||
getenv
|
getenv
|
||||||
getline
|
getline
|
||||||
|
getter
|
||||||
ggdb
|
ggdb
|
||||||
glibc
|
glibc
|
||||||
gmake
|
gmake
|
||||||
@@ -711,6 +732,7 @@ hh
|
|||||||
hier
|
hier
|
||||||
hierCMakeArgs
|
hierCMakeArgs
|
||||||
hierMkArgs
|
hierMkArgs
|
||||||
|
hierParameters
|
||||||
hierVer
|
hierVer
|
||||||
hx
|
hx
|
||||||
hyperthreading
|
hyperthreading
|
||||||
@@ -842,6 +864,8 @@ parallelized
|
|||||||
param
|
param
|
||||||
parameterization
|
parameterization
|
||||||
parameterized
|
parameterized
|
||||||
|
parameterized
|
||||||
|
parameterless
|
||||||
params
|
params
|
||||||
parens
|
parens
|
||||||
pawel
|
pawel
|
||||||
@@ -854,6 +878,7 @@ phelter
|
|||||||
picoChip
|
picoChip
|
||||||
pinIndex
|
pinIndex
|
||||||
pinout
|
pinout
|
||||||
|
pkgdatadir
|
||||||
plusargs
|
plusargs
|
||||||
pmos
|
pmos
|
||||||
poping
|
poping
|
||||||
@@ -885,7 +910,9 @@ profcfunc
|
|||||||
profiler
|
profiler
|
||||||
prototyptes
|
prototyptes
|
||||||
ps
|
ps
|
||||||
|
psprintf
|
||||||
pthread
|
pthread
|
||||||
|
pthreads
|
||||||
ptr
|
ptr
|
||||||
pulldown
|
pulldown
|
||||||
pulldowns
|
pulldowns
|
||||||
@@ -916,6 +943,7 @@ redeclaring
|
|||||||
regs
|
regs
|
||||||
reloop
|
reloop
|
||||||
replaceShiftOp
|
replaceShiftOp
|
||||||
|
reproducibility
|
||||||
resetall
|
resetall
|
||||||
respecified
|
respecified
|
||||||
rodata
|
rodata
|
||||||
@@ -968,6 +996,9 @@ submakes
|
|||||||
submodule
|
submodule
|
||||||
submodules
|
submodules
|
||||||
substring
|
substring
|
||||||
|
superclass
|
||||||
|
suspendable
|
||||||
|
suspendables
|
||||||
sv
|
sv
|
||||||
svBitVal
|
svBitVal
|
||||||
svBitVecVal
|
svBitVecVal
|
||||||
@@ -978,6 +1009,7 @@ svLogicVal
|
|||||||
svdpi
|
svdpi
|
||||||
svgGetTimeUnit
|
svgGetTimeUnit
|
||||||
swrite
|
swrite
|
||||||
|
synthesizeable
|
||||||
sys
|
sys
|
||||||
systemc
|
systemc
|
||||||
tenghtt
|
tenghtt
|
||||||
@@ -996,10 +1028,13 @@ toolchain
|
|||||||
topcell
|
topcell
|
||||||
toplevel
|
toplevel
|
||||||
toupper
|
toupper
|
||||||
|
traceCapable
|
||||||
traceEverOn
|
traceEverOn
|
||||||
tran
|
tran
|
||||||
treei
|
treei
|
||||||
tri
|
tri
|
||||||
|
triand
|
||||||
|
trior
|
||||||
tristate
|
tristate
|
||||||
tristates
|
tristates
|
||||||
trunc
|
trunc
|
||||||
@@ -1060,6 +1095,7 @@ vluint
|
|||||||
vpi
|
vpi
|
||||||
vpiConstType
|
vpiConstType
|
||||||
vpiDefName
|
vpiDefName
|
||||||
|
vpiInertialDelay
|
||||||
vpiInstance
|
vpiInstance
|
||||||
vpiLeftRange
|
vpiLeftRange
|
||||||
vpiModule
|
vpiModule
|
||||||
@@ -1074,6 +1110,7 @@ warmup
|
|||||||
waveforms
|
waveforms
|
||||||
whitespace
|
whitespace
|
||||||
widthed
|
widthed
|
||||||
|
wor
|
||||||
wreal
|
wreal
|
||||||
writeb
|
writeb
|
||||||
writeme
|
writeme
|
||||||
|
|||||||
@@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
|||||||
project(cmake_hello_c)
|
project(cmake_hello_c)
|
||||||
|
|
||||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||||
if (NOT verilator_FOUND)
|
if(NOT verilator_FOUND)
|
||||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Create a new executable target that will contain all your sources
|
# 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
|
# Add the Verilated circuit to the target
|
||||||
verilate(example
|
verilate(example
|
||||||
INCLUDE_DIRS "../make_hello_c"
|
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)
|
project(cmake_hello_sc CXX)
|
||||||
|
|
||||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||||
if (NOT verilator_FOUND)
|
if(NOT verilator_FOUND)
|
||||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# SystemC dependencies
|
# SystemC dependencies
|
||||||
@@ -39,14 +42,12 @@ find_package(SystemCLanguage QUIET)
|
|||||||
add_executable(example ../make_hello_sc/sc_main.cpp)
|
add_executable(example ../make_hello_sc/sc_main.cpp)
|
||||||
target_compile_features(example PUBLIC cxx_std_14)
|
target_compile_features(example PUBLIC cxx_std_14)
|
||||||
|
|
||||||
set_property(
|
set_property(TARGET example PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
|
||||||
TARGET example
|
|
||||||
PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add the Verilated circuit to the target
|
# Add the Verilated circuit to the target
|
||||||
verilate(example SYSTEMC
|
verilate(example SYSTEMC
|
||||||
INCLUDE_DIRS "../make_hello_sc"
|
INCLUDE_DIRS "../make_hello_sc"
|
||||||
SOURCES ../make_hello_sc/top.v)
|
SOURCES ../make_hello_sc/top.v
|
||||||
|
)
|
||||||
|
|
||||||
verilator_link_systemc(example)
|
verilator_link_systemc(example)
|
||||||
|
|||||||
@@ -24,8 +24,11 @@ cmake_policy(SET CMP0074 NEW)
|
|||||||
project(cmake_protect_lib)
|
project(cmake_protect_lib)
|
||||||
|
|
||||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||||
if (NOT verilator_FOUND)
|
if(NOT verilator_FOUND)
|
||||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Create the main executable target
|
# Create the main executable target
|
||||||
@@ -55,9 +58,11 @@ verilate(verilated_secret
|
|||||||
VERILATOR_ARGS --protect-lib verilated_secret
|
VERILATOR_ARGS --protect-lib verilated_secret
|
||||||
--protect-key ${PROTECT_KEY}
|
--protect-key ${PROTECT_KEY}
|
||||||
DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/verilated_secret
|
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
|
# Include location of verilated_secret.sv wrapper
|
||||||
verilate(example
|
verilate(example
|
||||||
VERILATOR_ARGS "-I${CMAKE_CURRENT_BINARY_DIR}/verilated_secret"
|
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)
|
project(cmake_tracing_c)
|
||||||
|
|
||||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||||
if (NOT verilator_FOUND)
|
if(NOT verilator_FOUND)
|
||||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Create a new executable target that will contain all your sources
|
# 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
|
verilate(example COVERAGE TRACE
|
||||||
INCLUDE_DIRS "../make_tracing_c"
|
INCLUDE_DIRS "../make_tracing_c"
|
||||||
VERILATOR_ARGS -f ../make_tracing_c/input.vc -x-assign fast
|
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)
|
project(cmake_tracing_sc_example CXX)
|
||||||
|
|
||||||
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT})
|
||||||
if (NOT verilator_FOUND)
|
if(NOT verilator_FOUND)
|
||||||
message(FATAL_ERROR "Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable")
|
message(
|
||||||
|
FATAL_ERROR
|
||||||
|
"Verilator was not found. Either install it, or set the VERILATOR_ROOT environment variable"
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# SystemC dependencies
|
# SystemC dependencies
|
||||||
@@ -40,15 +43,13 @@ find_package(SystemCLanguage QUIET)
|
|||||||
add_executable(example ../make_tracing_sc/sc_main.cpp)
|
add_executable(example ../make_tracing_sc/sc_main.cpp)
|
||||||
target_compile_features(example PUBLIC cxx_std_14)
|
target_compile_features(example PUBLIC cxx_std_14)
|
||||||
|
|
||||||
set_property(
|
set_property(TARGET example PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD})
|
||||||
TARGET example
|
|
||||||
PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Add the Verilated circuit to the target
|
# Add the Verilated circuit to the target
|
||||||
verilate(example SYSTEMC COVERAGE TRACE
|
verilate(example SYSTEMC COVERAGE TRACE
|
||||||
INCLUDE_DIRS "../make_tracing_sc"
|
INCLUDE_DIRS "../make_tracing_sc"
|
||||||
VERILATOR_ARGS -f ../make_tracing_sc/input.vc -x-assign fast
|
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)
|
verilator_link_systemc(example)
|
||||||
|
|||||||
@@ -13,6 +13,6 @@ module sub
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Some simple logic
|
// Some simple logic
|
||||||
always_comb out = ~ in;
|
always_comb out = ~in;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@@ -25,8 +25,7 @@ class VlFileCopy:
|
|||||||
|
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
|
|
||||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile(
|
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile() as meta_temp:
|
||||||
) as meta_temp:
|
|
||||||
vargs = [
|
vargs = [
|
||||||
'--json-only-output',
|
'--json-only-output',
|
||||||
tree_temp.name,
|
tree_temp.name,
|
||||||
@@ -61,8 +60,7 @@ class VlFileCopy:
|
|||||||
print("\t%s " % command)
|
print("\t%s " % command)
|
||||||
status = subprocess.call(command, shell=True)
|
status = subprocess.call(command, shell=True)
|
||||||
if status != 0:
|
if status != 0:
|
||||||
raise RuntimeError("Command failed running Verilator with '" +
|
raise RuntimeError("Command failed running Verilator with '" + command + "', stopped")
|
||||||
command + "', stopped")
|
|
||||||
|
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
@@ -71,8 +69,7 @@ if __name__ == '__main__':
|
|||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
description=
|
description="""Example of using Verilator JSON output to copy a list of files to an
|
||||||
"""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
|
output directory (-odir, defaults to 'copied'), e.g. to easily create a
|
||||||
tarball of the design to pass to others.
|
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.
|
any use, without warranty, 2019 by Wilson Snyder.
|
||||||
SPDX-License-Identifier: CC0-1.0
|
SPDX-License-Identifier: CC0-1.0
|
||||||
""")
|
""")
|
||||||
parser.add_argument('-debug',
|
parser.add_argument('-debug', '--debug', action='store_const', const=9, help='enable debug')
|
||||||
'--debug',
|
|
||||||
action='store_const',
|
|
||||||
const=9,
|
|
||||||
help='enable debug')
|
|
||||||
parser.add_argument('-odir',
|
parser.add_argument('-odir',
|
||||||
'--odir',
|
'--odir',
|
||||||
action='store',
|
action='store',
|
||||||
@@ -108,9 +101,7 @@ SPDX-License-Identifier: CC0-1.0
|
|||||||
help='target output directory')
|
help='target output directory')
|
||||||
(args, rem) = parser.parse_known_args()
|
(args, rem) = parser.parse_known_args()
|
||||||
|
|
||||||
print(
|
print("NOTE: vl_file_copy is only an example starting point for writing your own tool.")
|
||||||
"NOTE: vl_file_copy is only an example starting point for writing your own tool."
|
|
||||||
)
|
|
||||||
# That is:
|
# That is:
|
||||||
# 1. We will accept basic patches
|
# 1. We will accept basic patches
|
||||||
# 2. We are not expecting to make this globally useful. (e.g. we don't cleanup obj_dir)
|
# 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.next_vertex_number = 0
|
||||||
self.addr_to_number = {}
|
self.addr_to_number = {}
|
||||||
|
|
||||||
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile(
|
with NamedTemporaryFile() as tree_temp, NamedTemporaryFile() as meta_temp:
|
||||||
) as meta_temp:
|
|
||||||
vargs = [
|
vargs = [
|
||||||
'--json-only-output',
|
'--json-only-output',
|
||||||
tree_temp.name,
|
tree_temp.name,
|
||||||
@@ -45,9 +44,7 @@ class VlHierGraph:
|
|||||||
fh.write("digraph {\n")
|
fh.write("digraph {\n")
|
||||||
fh.write(" dpi=300;\n")
|
fh.write(" dpi=300;\n")
|
||||||
fh.write(" order=LR;\n")
|
fh.write(" order=LR;\n")
|
||||||
fh.write(
|
fh.write(" node [fontsize=8 shape=\"box\" margin=0.01 width=0 height=0]")
|
||||||
" node [fontsize=8 shape=\"box\" margin=0.01 width=0 height=0]"
|
|
||||||
)
|
|
||||||
fh.write(" edge [fontsize=6]")
|
fh.write(" edge [fontsize=6]")
|
||||||
# Find cells
|
# Find cells
|
||||||
modules = self.flatten(self.tree, lambda n: n['type'] == "MODULE")
|
modules = self.flatten(self.tree, lambda n: n['type'] == "MODULE")
|
||||||
@@ -101,8 +98,7 @@ class VlHierGraph:
|
|||||||
print("\t%s " % command)
|
print("\t%s " % command)
|
||||||
status = subprocess.call(command, shell=True)
|
status = subprocess.call(command, shell=True)
|
||||||
if status != 0:
|
if status != 0:
|
||||||
raise RuntimeError("Command failed running Verilator with '" +
|
raise RuntimeError("Command failed running Verilator with '" + command + "', stopped")
|
||||||
command + "', stopped")
|
|
||||||
|
|
||||||
|
|
||||||
#######################################################################
|
#######################################################################
|
||||||
@@ -111,8 +107,7 @@ if __name__ == '__main__':
|
|||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawTextHelpFormatter,
|
formatter_class=argparse.RawTextHelpFormatter,
|
||||||
description=
|
description="""Example of using Verilator JSON output to create a .dot file showing the
|
||||||
"""Example of using Verilator JSON output to create a .dot file showing the
|
|
||||||
design module hierarchy.
|
design module hierarchy.
|
||||||
|
|
||||||
Example usage:
|
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.
|
any use, without warranty, 2019 by Wilson Snyder.
|
||||||
SPDX-License-Identifier: CC0-1.0
|
SPDX-License-Identifier: CC0-1.0
|
||||||
""")
|
""")
|
||||||
parser.add_argument('-debug',
|
parser.add_argument('-debug', '--debug', action='store_const', const=9, help='enable debug')
|
||||||
'--debug',
|
|
||||||
action='store_const',
|
|
||||||
const=9,
|
|
||||||
help='enable debug')
|
|
||||||
parser.add_argument('-o',
|
parser.add_argument('-o',
|
||||||
'--o',
|
'--o',
|
||||||
action='store',
|
action='store',
|
||||||
@@ -147,18 +138,14 @@ SPDX-License-Identifier: CC0-1.0
|
|||||||
help='output filename')
|
help='output filename')
|
||||||
(args, rem) = parser.parse_known_args()
|
(args, rem) = parser.parse_known_args()
|
||||||
|
|
||||||
print(
|
print("NOTE: vl_hier_graph is only an example starting point for writing your own tool.")
|
||||||
"NOTE: vl_hier_graph is only an example starting point for writing your own tool."
|
|
||||||
)
|
|
||||||
# That is:
|
# That is:
|
||||||
# 1. We will accept basic patches
|
# 1. We will accept basic patches
|
||||||
# 2. We are not expecting to make this globally useful. (e.g. we don't cleanup obj_dir)
|
# 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.
|
# 3. "make install" will not install this.
|
||||||
# 4. This has not had production-worthy validation.
|
# 4. This has not had production-worthy validation.
|
||||||
|
|
||||||
fc = VlHierGraph(output_filename=args.o,
|
fc = VlHierGraph(output_filename=args.o, debug=args.debug, verilator_args=rem)
|
||||||
debug=args.debug,
|
|
||||||
verilator_args=rem)
|
|
||||||
|
|
||||||
######################################################################
|
######################################################################
|
||||||
# Local Variables:
|
# Local Variables:
|
||||||
|
|||||||
@@ -47,12 +47,12 @@ int main(int argc, char** argv) {
|
|||||||
|
|
||||||
// Simulate until $finish
|
// Simulate until $finish
|
||||||
while (!contextp->gotFinish()) {
|
while (!contextp->gotFinish()) {
|
||||||
contextp->timeInc(1);
|
|
||||||
top->clk = ~top->clk & 0x1;
|
top->clk = ~top->clk & 0x1;
|
||||||
top->eval();
|
top->eval();
|
||||||
#if VM_TRACE
|
#if VM_TRACE
|
||||||
if (tfp) tfp->dump(contextp->time());
|
if (tfp) tfp->dump(contextp->time());
|
||||||
#endif
|
#endif
|
||||||
|
contextp->timeInc(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Final model cleanup
|
// Final model cleanup
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ module sub
|
|||||||
|
|
||||||
// Example counter/flop
|
// Example counter/flop
|
||||||
reg [31:0] count_c;
|
reg [31:0] count_c;
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
if (!reset_l) begin
|
if (!reset_l) begin
|
||||||
/*AUTORESET*/
|
/*AUTORESET*/
|
||||||
// Beginning of autoreset for uninitialized flops
|
// Beginning of autoreset for uninitialized flops
|
||||||
@@ -32,11 +32,11 @@ module sub
|
|||||||
end
|
end
|
||||||
|
|
||||||
// An example assertion
|
// An example assertion
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
AssertionExample: assert (!reset_l || count_c<100);
|
AssertionExample : assert (!reset_l || count_c < 100);
|
||||||
end
|
end
|
||||||
|
|
||||||
// And example coverage analysis
|
// And example coverage analysis
|
||||||
cover property (@(posedge clk) count_c==3);
|
cover property (@(posedge clk) count_c == 3);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ module sub
|
|||||||
|
|
||||||
// Example counter/flop
|
// Example counter/flop
|
||||||
reg [31:0] count_f;
|
reg [31:0] count_f;
|
||||||
always_ff @ (posedge fastclk) begin
|
always_ff @(posedge fastclk) begin
|
||||||
if (!reset_l) begin
|
if (!reset_l) begin
|
||||||
/*AUTORESET*/
|
/*AUTORESET*/
|
||||||
// Beginning of autoreset for uninitialized flops
|
// Beginning of autoreset for uninitialized flops
|
||||||
@@ -28,7 +28,7 @@ module sub
|
|||||||
|
|
||||||
// Another example flop
|
// Another example flop
|
||||||
reg [31:0] count_c;
|
reg [31:0] count_c;
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
if (!reset_l) begin
|
if (!reset_l) begin
|
||||||
/*AUTORESET*/
|
/*AUTORESET*/
|
||||||
// Beginning of autoreset for uninitialized flops
|
// Beginning of autoreset for uninitialized flops
|
||||||
@@ -38,8 +38,7 @@ module sub
|
|||||||
else begin
|
else begin
|
||||||
count_c <= count_c + 1;
|
count_c <= count_c + 1;
|
||||||
if (count_c >= 3) begin
|
if (count_c >= 3) begin
|
||||||
$display("[%0t] fastclk is %0d times faster than clk\n",
|
$display("[%0t] fastclk is %0d times faster than clk\n", $time, count_f / count_c);
|
||||||
$time, count_f/count_c);
|
|
||||||
// This write is a magic value the Makefile uses to make sure the
|
// This write is a magic value the Makefile uses to make sure the
|
||||||
// test completes successfully.
|
// test completes successfully.
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
@@ -49,11 +48,11 @@ module sub
|
|||||||
end
|
end
|
||||||
|
|
||||||
// An example assertion
|
// An example assertion
|
||||||
always_ff @ (posedge clk) begin
|
always_ff @(posedge clk) begin
|
||||||
AssertionExample: assert(!reset_l || count_c<100);
|
AssertionExample : assert (!reset_l || count_c < 100);
|
||||||
end
|
end
|
||||||
|
|
||||||
// And example coverage analysis
|
// And example coverage analysis
|
||||||
cover property (@(posedge clk) count_c==3);
|
cover property (@(posedge clk) count_c == 3);
|
||||||
|
|
||||||
endmodule
|
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_HDR_TIMEZERO_SIZE (8)
|
||||||
#define FST_GZIO_LEN (32768)
|
#define FST_GZIO_LEN (32768)
|
||||||
#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
|
#define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024)
|
||||||
|
#define FST_ZWRAPPER_HDR_SIZE (1+8+8)
|
||||||
|
|
||||||
#if defined(__APPLE__) && defined(__MACH__)
|
#if defined(__APPLE__) && defined(__MACH__)
|
||||||
#define FST_MACOSX
|
#define FST_MACOSX
|
||||||
@@ -347,8 +348,9 @@ return(NULL);
|
|||||||
|
|
||||||
static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
|
static void *fstMmap2(size_t __len, int __fd, fst_off_t __off)
|
||||||
{
|
{
|
||||||
|
DWORD64 len64 = __len; /* Must be 64-bit for shift below */
|
||||||
HANDLE handle = CreateFileMapping((HANDLE)_get_osfhandle(__fd), NULL,
|
HANDLE handle = CreateFileMapping((HANDLE)_get_osfhandle(__fd), NULL,
|
||||||
PAGE_READWRITE, (DWORD)(__len >> 32),
|
PAGE_READWRITE, (DWORD)(len64 >> 32),
|
||||||
(DWORD)__len, NULL);
|
(DWORD)__len, NULL);
|
||||||
if (!handle) { return NULL; }
|
if (!handle) { return NULL; }
|
||||||
|
|
||||||
@@ -548,8 +550,9 @@ return(rc);
|
|||||||
|
|
||||||
static uint32_t fstReaderVarint32(FILE *f)
|
static uint32_t fstReaderVarint32(FILE *f)
|
||||||
{
|
{
|
||||||
int chk_len = 5; /* TALOS-2023-1783 */
|
const int chk_len_max = 5; /* TALOS-2023-1783 */
|
||||||
unsigned char buf[chk_len];
|
int chk_len = chk_len_max;
|
||||||
|
unsigned char buf[chk_len_max];
|
||||||
unsigned char *mem = buf;
|
unsigned char *mem = buf;
|
||||||
uint32_t rc = 0;
|
uint32_t rc = 0;
|
||||||
int ch;
|
int ch;
|
||||||
@@ -580,8 +583,9 @@ return(rc);
|
|||||||
|
|
||||||
static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
|
static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen)
|
||||||
{
|
{
|
||||||
int chk_len = 5; /* TALOS-2023-1783 */
|
const int chk_len_max = 5; /* TALOS-2023-1783 */
|
||||||
unsigned char buf[chk_len];
|
int chk_len = chk_len_max;
|
||||||
|
unsigned char buf[chk_len_max];
|
||||||
unsigned char *mem = buf;
|
unsigned char *mem = buf;
|
||||||
uint32_t rc = 0;
|
uint32_t rc = 0;
|
||||||
int ch;
|
int ch;
|
||||||
@@ -613,8 +617,9 @@ return(rc);
|
|||||||
|
|
||||||
static uint64_t fstReaderVarint64(FILE *f)
|
static uint64_t fstReaderVarint64(FILE *f)
|
||||||
{
|
{
|
||||||
int chk_len = 16; /* TALOS-2023-1783 */
|
const int chk_len_max = 16; /* TALOS-2023-1783 */
|
||||||
unsigned char buf[chk_len];
|
int chk_len = chk_len_max;
|
||||||
|
unsigned char buf[chk_len_max];
|
||||||
unsigned char *mem = buf;
|
unsigned char *mem = buf;
|
||||||
uint64_t rc = 0;
|
uint64_t rc = 0;
|
||||||
int ch;
|
int ch;
|
||||||
@@ -4632,9 +4637,14 @@ if(sectype == FST_BL_ZWRAPPER)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
fstReaderFseeko(xc, xc->f, 1+8+8, SEEK_SET);
|
fstReaderFseeko(xc, xc->f, FST_ZWRAPPER_HDR_SIZE, SEEK_SET);
|
||||||
#ifndef __MINGW32__
|
#ifndef __MINGW32__
|
||||||
fflush(xc->f);
|
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
|
#endif
|
||||||
|
|
||||||
zfd = dup(fileno(xc->f));
|
zfd = dup(fileno(xc->f));
|
||||||
@@ -6184,7 +6194,9 @@ struct fstReaderContext *xc = (struct fstReaderContext *)ctx;
|
|||||||
fst_off_t blkpos = 0, prev_blkpos;
|
fst_off_t blkpos = 0, prev_blkpos;
|
||||||
uint64_t beg_tim, end_tim, beg_tim2, end_tim2;
|
uint64_t beg_tim, end_tim, beg_tim2, end_tim2;
|
||||||
int sectype;
|
int sectype;
|
||||||
|
#ifdef FST_DEBUG
|
||||||
unsigned int secnum = 0;
|
unsigned int secnum = 0;
|
||||||
|
#endif
|
||||||
uint64_t seclen;
|
uint64_t seclen;
|
||||||
uint64_t tsec_uclen = 0, tsec_clen = 0;
|
uint64_t tsec_uclen = 0, tsec_clen = 0;
|
||||||
uint64_t tsec_nitems;
|
uint64_t tsec_nitems;
|
||||||
@@ -6276,7 +6288,9 @@ for(;;)
|
|||||||
}
|
}
|
||||||
|
|
||||||
blkpos += seclen;
|
blkpos += seclen;
|
||||||
|
#ifdef FST_DEBUG
|
||||||
secnum++;
|
secnum++;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
xc->rvat_beg_tim = beg_tim;
|
xc->rvat_beg_tim = beg_tim;
|
||||||
|
|||||||
+145
-65
@@ -82,6 +82,12 @@
|
|||||||
|
|
||||||
#include "verilated_trace.h"
|
#include "verilated_trace.h"
|
||||||
|
|
||||||
|
#ifdef VM_SOLVER_DEFAULT
|
||||||
|
#define VL_SOLVER_DEFAULT VM_SOLVER_DEFAULT
|
||||||
|
#else
|
||||||
|
#define VL_SOLVER_DEFAULT "z3 --in"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Max characters in static char string for VL_VALUE_STRING
|
// Max characters in static char string for VL_VALUE_STRING
|
||||||
constexpr unsigned VL_VALUE_STRING_MAX_WIDTH = 8192;
|
constexpr unsigned VL_VALUE_STRING_MAX_WIDTH = 8192;
|
||||||
|
|
||||||
@@ -122,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
|
#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 {
|
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";
|
const char* const msg = "Verilog $stop";
|
||||||
Verilated::threadContextp()->gotError(true);
|
Verilated::threadContextp()->gotError(true);
|
||||||
Verilated::threadContextp()->gotFinish(true);
|
Verilated::threadContextp()->gotFinish(true);
|
||||||
@@ -166,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
|
#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 {
|
void vl_stop_maybe(const char* filename, int linenum, const char* hier, bool maybe) VL_MT_UNSAFE {
|
||||||
|
// $stop or $fatal
|
||||||
Verilated::threadContextp()->errorCountInc();
|
Verilated::threadContextp()->errorCountInc();
|
||||||
if (maybe
|
if (maybe
|
||||||
&& Verilated::threadContextp()->errorCount() < Verilated::threadContextp()->errorLimit()) {
|
&& Verilated::threadContextp()->errorCount() < Verilated::threadContextp()->errorLimit()) {
|
||||||
@@ -406,6 +414,8 @@ IData VL_RAND_RESET_I(int obits) VL_MT_SAFE {
|
|||||||
data &= VL_MASK_I(obits);
|
data &= VL_MASK_I(obits);
|
||||||
return data;
|
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 {
|
QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
||||||
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
if (Verilated::threadContextp()->randReset() == 0) return 0;
|
||||||
QData data = ~0ULL;
|
QData data = ~0ULL;
|
||||||
@@ -415,11 +425,19 @@ QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE {
|
|||||||
data &= VL_MASK_Q(obits);
|
data &= VL_MASK_Q(obits);
|
||||||
return data;
|
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 {
|
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);
|
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);
|
outwp[VL_WORDS_I(obits) - 1] = VL_RAND_RESET_I(32) & VL_MASK_E(obits);
|
||||||
return outwp;
|
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 {
|
WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE {
|
||||||
// Not inlined to speed up compilation of slowpath code
|
// Not inlined to speed up compilation of slowpath code
|
||||||
return VL_ZERO_W(obits, outwp);
|
return VL_ZERO_W(obits, outwp);
|
||||||
@@ -1171,8 +1189,8 @@ static char* _vl_vsss_read_bin(FILE* fp, int& floc, const WDataInP fromp, const
|
|||||||
static void _vl_vsss_setbit(WDataOutP iowp, int obits, int lsb, int nbits, IData ld) VL_MT_SAFE {
|
static void _vl_vsss_setbit(WDataOutP iowp, int obits, int lsb, int nbits, IData ld) VL_MT_SAFE {
|
||||||
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) VL_ASSIGNBIT_WI(lsb, iowp, ld & 1);
|
for (; nbits && lsb < obits; nbits--, lsb++, ld >>= 1) VL_ASSIGNBIT_WI(lsb, iowp, ld & 1);
|
||||||
}
|
}
|
||||||
static void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp,
|
void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp, size_t posstart,
|
||||||
size_t posstart, size_t posend) VL_MT_SAFE {
|
size_t posend) VL_MT_SAFE {
|
||||||
// Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits.
|
// Read in base "2^^baseLog2" digits from strp[posstart..posend-1] into owp of size obits.
|
||||||
VL_ZERO_W(obits, owp);
|
VL_ZERO_W(obits, owp);
|
||||||
int lsb = 0;
|
int lsb = 0;
|
||||||
@@ -1747,9 +1765,11 @@ IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
|
|||||||
return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw);
|
return VL_SYSTEM_IW(VL_WQ_WORDS_E, lhsw);
|
||||||
}
|
}
|
||||||
IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE {
|
IData VL_SYSTEM_IW(int lhswords, const WDataInP lhsp) VL_MT_SAFE {
|
||||||
char filenamez[VL_VALUE_STRING_MAX_CHARS + 1];
|
const std::string lhs = VL_CVT_PACK_STR_NW(lhswords, lhsp);
|
||||||
_vl_vint_to_string(lhswords * VL_EDATASIZE, filenamez, lhsp);
|
return VL_SYSTEM_IN(lhs);
|
||||||
const int code = std::system(filenamez); // Yes, std::system() is threadsafe
|
}
|
||||||
|
IData VL_SYSTEM_IN(const std::string& lhs) VL_MT_SAFE {
|
||||||
|
const int code = std::system(lhs.c_str()); // Yes, std::system() is threadsafe
|
||||||
return code >> 8; // Want exit status
|
return code >> 8; // Want exit status
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1896,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 {
|
std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_PURE {
|
||||||
// See also _vl_vint_to_string
|
// 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;
|
const int obits = lwords * VL_EDATASIZE;
|
||||||
int lsb = obits - 1;
|
int lsb = obits - 1;
|
||||||
char* destp = destout;
|
|
||||||
size_t len = 0;
|
|
||||||
for (; lsb >= 0; --lsb) {
|
for (; lsb >= 0; --lsb) {
|
||||||
lsb = (lsb / 8) * 8; // Next digit
|
lsb = (lsb / 8) * 8; // Next digit
|
||||||
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
|
||||||
if (charval) {
|
if (charval) result += static_cast<char>(charval);
|
||||||
*destp++ = static_cast<char>(charval);
|
|
||||||
++len;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return std::string{destout, len};
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string VL_CVT_PACK_STR_ND(const VlQueue<std::string>& q) VL_PURE {
|
std::string VL_CVT_PACK_STR_ND(const VlQueue<std::string>& q) VL_PURE {
|
||||||
@@ -2037,22 +2053,26 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
|
|||||||
if (VL_UNLIKELY(!m_fp)) return false;
|
if (VL_UNLIKELY(!m_fp)) return false;
|
||||||
valuer = "";
|
valuer = "";
|
||||||
// Prep for reading
|
// Prep for reading
|
||||||
bool indata = false;
|
bool inData = false;
|
||||||
bool ignore_to_eol = false;
|
bool ignoreToEol = false;
|
||||||
bool ignore_to_cmt = false;
|
bool ignoreToComment = false;
|
||||||
bool reading_addr = false;
|
bool readingAddress = false;
|
||||||
int lastc = ' ';
|
int lastCh = ' ';
|
||||||
// Read the data
|
// Read the data
|
||||||
// We process a character at a time, as then we don't need to deal
|
// We process a character at a time, as then we don't need to deal
|
||||||
// with changing buffer sizes dynamically, etc.
|
// with changing buffer sizes dynamically, etc.
|
||||||
while (true) {
|
while (true) {
|
||||||
int c = std::fgetc(m_fp);
|
int c = std::fgetc(m_fp);
|
||||||
if (VL_UNLIKELY(c == EOF)) break;
|
if (VL_UNLIKELY(c == EOF)) break;
|
||||||
|
const bool chIs4StateBin
|
||||||
|
= c == '0' || c == '1' || c == 'x' || c == 'X' || c == 'z' || c == 'Z';
|
||||||
|
const bool chIs2StateHex = std::isxdigit(c);
|
||||||
|
const bool chIs4StateHex = std::isxdigit(c) || chIs4StateBin;
|
||||||
// printf("%d: Got '%c' Addr%lx IN%d IgE%d IgC%d\n",
|
// printf("%d: Got '%c' Addr%lx IN%d IgE%d IgC%d\n",
|
||||||
// m_linenum, c, m_addr, indata, ignore_to_eol, ignore_to_cmt);
|
// m_linenum, c, m_addr, inData, ignoreToEol, ignoreToComment);
|
||||||
// See if previous data value has completed, and if so return
|
// See if previous data value has completed, and if so return
|
||||||
if (c == '_') continue; // Ignore _ e.g. inside a number
|
if (c == '_') continue; // Ignore _ e.g. inside a number
|
||||||
if (indata && !std::isxdigit(c) && c != 'x' && c != 'X') {
|
if (inData && !chIs4StateHex) {
|
||||||
// printf("Got data @%lx = %s\n", m_addr, valuer.c_str());
|
// printf("Got data @%lx = %s\n", m_addr, valuer.c_str());
|
||||||
ungetc(c, m_fp);
|
ungetc(c, m_fp);
|
||||||
addrr = m_addr;
|
addrr = m_addr;
|
||||||
@@ -2062,50 +2082,46 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
|
|||||||
// Parse line
|
// Parse line
|
||||||
if (c == '\n') {
|
if (c == '\n') {
|
||||||
++m_linenum;
|
++m_linenum;
|
||||||
ignore_to_eol = false;
|
ignoreToEol = false;
|
||||||
reading_addr = false;
|
readingAddress = false;
|
||||||
} else if (c == '\t' || c == ' ' || c == '\r' || c == '\f') {
|
} else if (c == '\t' || c == ' ' || c == '\r' || c == '\f') {
|
||||||
reading_addr = false;
|
readingAddress = false;
|
||||||
}
|
}
|
||||||
// Skip // comments and detect /* comments
|
// Skip // comments and detect /* comments
|
||||||
else if (ignore_to_cmt && lastc == '*' && c == '/') {
|
else if (ignoreToComment && lastCh == '*' && c == '/') {
|
||||||
ignore_to_cmt = false;
|
ignoreToComment = false;
|
||||||
reading_addr = false;
|
readingAddress = false;
|
||||||
} else if (!ignore_to_eol && !ignore_to_cmt) {
|
} else if (!ignoreToEol && !ignoreToComment) {
|
||||||
if (lastc == '/' && c == '*') {
|
if (lastCh == '/' && c == '*') {
|
||||||
ignore_to_cmt = true;
|
ignoreToComment = true;
|
||||||
} else if (lastc == '/' && c == '/') {
|
} else if (lastCh == '/' && c == '/') {
|
||||||
ignore_to_eol = true;
|
ignoreToEol = true;
|
||||||
} else if (c == '/') { // Part of /* or //
|
} else if (c == '/') { // Part of /* or //
|
||||||
} else if (c == '#') {
|
} else if (c == '#') {
|
||||||
ignore_to_eol = true;
|
ignoreToEol = true;
|
||||||
} else if (c == '@') {
|
} else if (c == '@') {
|
||||||
reading_addr = true;
|
readingAddress = true;
|
||||||
m_anyAddr = true;
|
m_anyAddr = true;
|
||||||
m_addr = 0;
|
m_addr = 0;
|
||||||
}
|
} else if (readingAddress && chIs2StateHex) {
|
||||||
// Check for hex or binary digits as file format requests
|
|
||||||
else if (std::isxdigit(c) || (!reading_addr && (c == 'x' || c == 'X'))) {
|
|
||||||
c = std::tolower(c);
|
c = std::tolower(c);
|
||||||
const int value
|
const int addressValue = (c >= 'a') ? (c - 'a' + 10) : (c - '0');
|
||||||
= (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0'));
|
m_addr = (m_addr << 4) + addressValue;
|
||||||
if (reading_addr) {
|
} else if (readingAddress && chIs4StateHex) {
|
||||||
// Decode @ addresses
|
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
|
||||||
m_addr = (m_addr << 4) + value;
|
"$readmem address contains 4-state characters");
|
||||||
} else {
|
} else if (chIs4StateHex) {
|
||||||
indata = true;
|
inData = true;
|
||||||
valuer += static_cast<char>(c);
|
valuer += static_cast<char>(c);
|
||||||
// printf(" Value width=%d @%x = %c\n", width, m_addr, c);
|
if (VL_UNLIKELY(!m_hex && !chIs4StateBin)) {
|
||||||
if (VL_UNLIKELY(value > 1 && !m_hex)) {
|
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
|
||||||
VL_FATAL_MT(m_filename.c_str(), m_linenum, "",
|
"$readmemb (binary) file contains hex characters");
|
||||||
"$readmemb (binary) file contains hex characters");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
VL_FATAL_MT(m_filename.c_str(), m_linenum, "", "$readmem file syntax error");
|
VL_FATAL_MT(m_filename.c_str(), m_linenum, "", "$readmem file syntax error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastc = c;
|
lastCh = c;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (VL_UNLIKELY(m_end != ~0ULL && m_addr <= m_end && !m_anyAddr)) {
|
if (VL_UNLIKELY(m_end != ~0ULL && m_addr <= m_end && !m_anyAddr)) {
|
||||||
@@ -2114,7 +2130,7 @@ bool VlReadMem::get(QData& addrr, std::string& valuer) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addrr = m_addr;
|
addrr = m_addr;
|
||||||
return indata; // EOF
|
return inData; // EOF
|
||||||
}
|
}
|
||||||
void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
||||||
const QData shift = m_hex ? 4ULL : 1ULL;
|
const QData shift = m_hex ? 4ULL : 1ULL;
|
||||||
@@ -2122,8 +2138,9 @@ void VlReadMem::setData(void* valuep, const std::string& rhs) {
|
|||||||
// Shift value in
|
// Shift value in
|
||||||
for (const auto& i : rhs) {
|
for (const auto& i : rhs) {
|
||||||
const char c = std::tolower(i);
|
const char c = std::tolower(i);
|
||||||
const int value
|
const int value = (c == 'x' || c == 'z') ? VL_RAND_RESET_I(m_hex ? 4 : 1)
|
||||||
= (c >= 'a' ? (c == 'x' ? VL_RAND_RESET_I(4) : (c - 'a' + 10)) : (c - '0'));
|
: (c >= 'a') ? (c - 'a' + 10)
|
||||||
|
: (c - '0');
|
||||||
if (m_bits <= 8) {
|
if (m_bits <= 8) {
|
||||||
CData* const datap = reinterpret_cast<CData*>(valuep);
|
CData* const datap = reinterpret_cast<CData*>(valuep);
|
||||||
if (!innum) *datap = 0;
|
if (!innum) *datap = 0;
|
||||||
@@ -2457,6 +2474,7 @@ VerilatedContext::VerilatedContext()
|
|||||||
m_ns.m_coverageFilename = "coverage.dat";
|
m_ns.m_coverageFilename = "coverage.dat";
|
||||||
m_ns.m_profExecFilename = "profile_exec.dat";
|
m_ns.m_profExecFilename = "profile_exec.dat";
|
||||||
m_ns.m_profVltFilename = "profile.vlt";
|
m_ns.m_profVltFilename = "profile.vlt";
|
||||||
|
m_ns.m_solverProgram = VlOs::getenvStr("VERILATOR_SOLVER", VL_SOLVER_DEFAULT);
|
||||||
m_fdps.resize(31);
|
m_fdps.resize(31);
|
||||||
std::fill(m_fdps.begin(), m_fdps.end(), static_cast<FILE*>(nullptr));
|
std::fill(m_fdps.begin(), m_fdps.end(), static_cast<FILE*>(nullptr));
|
||||||
m_fdFreeMct.resize(30);
|
m_fdFreeMct.resize(30);
|
||||||
@@ -2483,9 +2501,47 @@ VerilatedContext::Serialized::Serialized() {
|
|||||||
m_timeprecision = picosecond; // Initial value until overridden by _Vconfigure
|
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 {
|
void VerilatedContext::assertOn(bool flag) VL_MT_SAFE {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
// Set all assert and directive types when true, clear otherwise.
|
||||||
m_s.m_assertOn = flag;
|
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 {
|
void VerilatedContext::calcUnusedSigs(bool flag) VL_MT_SAFE {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
@@ -2567,6 +2623,14 @@ std::string VerilatedContext::profVltFilename() const VL_MT_SAFE {
|
|||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
return m_ns.m_profVltFilename;
|
return m_ns.m_profVltFilename;
|
||||||
}
|
}
|
||||||
|
void VerilatedContext::solverProgram(const std::string& flag) VL_MT_SAFE {
|
||||||
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
|
m_ns.m_solverProgram = flag;
|
||||||
|
}
|
||||||
|
std::string VerilatedContext::solverProgram() const VL_MT_SAFE {
|
||||||
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
|
return m_ns.m_solverProgram;
|
||||||
|
}
|
||||||
void VerilatedContext::quiet(bool flag) VL_MT_SAFE {
|
void VerilatedContext::quiet(bool flag) VL_MT_SAFE {
|
||||||
const VerilatedLockGuard lock{m_mutex};
|
const VerilatedLockGuard lock{m_mutex};
|
||||||
m_s.m_quiet = flag;
|
m_s.m_quiet = flag;
|
||||||
@@ -2645,8 +2709,16 @@ void VerilatedContext::addModel(VerilatedModel* modelp) {
|
|||||||
m_ns.m_cpuTimeStart.start();
|
m_ns.m_cpuTimeStart.start();
|
||||||
m_ns.m_wallTimeStart.start();
|
m_ns.m_wallTimeStart.start();
|
||||||
}
|
}
|
||||||
threadPoolp(); // Ensure thread pool is created, so m_threads cannot change any more
|
|
||||||
|
|
||||||
|
// We look for time passing, as opposed to post-eval(), as embedded
|
||||||
|
// models might get added inside initial blocks.
|
||||||
|
if (VL_UNLIKELY(time()))
|
||||||
|
VL_FATAL_MT(
|
||||||
|
"", 0, "",
|
||||||
|
"Adding model when time is non-zero. ... Suggest check time(), or for restarting"
|
||||||
|
" model use a new VerilatedContext");
|
||||||
|
|
||||||
|
threadPoolp(); // Ensure thread pool is created, so m_threads cannot change any more
|
||||||
m_threadsInModels += modelp->threads();
|
m_threadsInModels += modelp->threads();
|
||||||
if (VL_UNLIKELY(modelp->threads() > m_threads)) {
|
if (VL_UNLIKELY(modelp->threads() > m_threads)) {
|
||||||
std::ostringstream msg;
|
std::ostringstream msg;
|
||||||
@@ -2882,7 +2954,7 @@ void VerilatedContext::statsPrintSummary() VL_MT_UNSAFE {
|
|||||||
VL_PRINTF("- Verilator: %s at %s; walltime %0.3f s; speed %s/s\n", endwhy.c_str(),
|
VL_PRINTF("- Verilator: %s at %s; walltime %0.3f s; speed %s/s\n", endwhy.c_str(),
|
||||||
simtime.c_str(), walltime, simtimePerf.c_str());
|
simtime.c_str(), walltime, simtimePerf.c_str());
|
||||||
const double modelMB = VlOs::memUsageBytes() / 1024.0 / 1024.0;
|
const double modelMB = VlOs::memUsageBytes() / 1024.0 / 1024.0;
|
||||||
VL_PRINTF("- Verilator: cpu %0.3f s on %d threads; alloced %0.0f MB\n", cputime,
|
VL_PRINTF("- Verilator: cpu %0.3f s on %u threads; alloced %0.0f MB\n", cputime,
|
||||||
threadsInModels(), modelMB);
|
threadsInModels(), modelMB);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2927,13 +2999,12 @@ const VerilatedScopeNameMap* VerilatedContext::scopeNameMap() VL_MT_SAFE {
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// VerilatedContext:: Methods - trace
|
// 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"););
|
VL_DEBUG_IF(VL_DBG_MSGF("+ VerilatedContext::trace\n"););
|
||||||
if (tfp->isOpen()) {
|
if (tfp->isOpen()) {
|
||||||
VL_FATAL_MT("", 0, "",
|
VL_FATAL_MT("", 0, "",
|
||||||
"Testbench C call to 'VerilatedContext::trace()' must not be called"
|
"Testbench C call to 'VerilatedContext::trace()' must not be called"
|
||||||
" after 'VerilatedTrace*::open()'\n");
|
" after 'VerilatedTrace*::open()'\n");
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
// Legacy usage may call {modela}->trace(...) then {modelb}->trace(...)
|
// Legacy usage may call {modela}->trace(...) then {modelb}->trace(...)
|
||||||
@@ -3126,12 +3197,21 @@ void Verilated::stackCheck(QData needSize) VL_MT_UNSAFE {
|
|||||||
if (haveSize == RLIM_INFINITY) haveSize = 0;
|
if (haveSize == RLIM_INFINITY) haveSize = 0;
|
||||||
}
|
}
|
||||||
// VL_PRINTF_MT("-Info: stackCheck(%" PRIu64 ") have %" PRIu64 "\n", needSize, haveSize);
|
// VL_PRINTF_MT("-Info: stackCheck(%" PRIu64 ") have %" PRIu64 "\n", needSize, haveSize);
|
||||||
// Check for 1.5x need, but suggest 2x so small model increase won't cause warning
|
// Check and request for 1.5x need. This is automated so the user doesn't need to do anything.
|
||||||
// if the user follows the suggestions
|
QData requestSize = needSize + needSize / 2;
|
||||||
if (VL_UNLIKELY(haveSize && needSize && haveSize < (needSize + needSize / 2))) {
|
if (VL_UNLIKELY(haveSize && needSize && haveSize < requestSize)) {
|
||||||
VL_PRINTF_MT("%%Warning: System has stack size %" PRIu64 " kb"
|
// Try to increase the stack limit to the requested size
|
||||||
" which may be too small; suggest 'ulimit -s %" PRIu64 "' or larger\n",
|
rlim.rlim_cur = requestSize;
|
||||||
haveSize / 1024, (needSize * 2) / 1024);
|
if (
|
||||||
|
#ifdef _VL_TEST_RLIMIT_FAIL
|
||||||
|
true ||
|
||||||
|
#endif
|
||||||
|
setrlimit(RLIMIT_STACK, &rlim)) {
|
||||||
|
VL_PRINTF_MT("%%Warning: System has stack size %" PRIu64 " kb"
|
||||||
|
" which may be too small; failed to request more"
|
||||||
|
" using 'ulimit -s %" PRIu64 "'\n",
|
||||||
|
haveSize / 1024, requestSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
(void)needSize; // Unused argument
|
(void)needSize; // Unused argument
|
||||||
|
|||||||
+112
-73
@@ -55,6 +55,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <deque>
|
#include <deque>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <limits>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
@@ -153,6 +154,27 @@ enum VerilatedVarFlags {
|
|||||||
VLVF_DPI_CLAY = (1 << 10) // DPI compatible C standard layout
|
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
|
// Utility functions
|
||||||
|
|
||||||
@@ -199,19 +221,6 @@ public:
|
|||||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
|
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); }
|
||||||
/// Try to acquire mutex. Returns true on success, and false on failure.
|
/// 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(); }
|
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
|
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||||
@@ -347,6 +356,19 @@ public:
|
|||||||
class VerilatedContext VL_NOT_FINAL {
|
class VerilatedContext VL_NOT_FINAL {
|
||||||
friend class VerilatedContextImp;
|
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:
|
protected:
|
||||||
// TYPES
|
// TYPES
|
||||||
using traceBaseModelCb_t
|
using traceBaseModelCb_t
|
||||||
@@ -360,7 +382,11 @@ protected:
|
|||||||
// No std::strings or pointers or will serialize badly!
|
// No std::strings or pointers or will serialize badly!
|
||||||
// Fast path
|
// Fast path
|
||||||
uint64_t m_time = 0; // Current $time (unscaled), 0=at zero, or legacy
|
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_calcUnusedSigs = false; // Waves file on, need all signals calculated
|
||||||
bool m_fatalOnError = true; // Fatal on $stop/non-fatal error
|
bool m_fatalOnError = true; // Fatal on $stop/non-fatal error
|
||||||
bool m_fatalOnVpiError = true; // Fatal on vpi error/unsupported
|
bool m_fatalOnVpiError = true; // Fatal on vpi error/unsupported
|
||||||
@@ -396,6 +422,7 @@ protected:
|
|||||||
std::string m_coverageFilename; // +coverage+file filename
|
std::string m_coverageFilename; // +coverage+file filename
|
||||||
std::string m_profExecFilename; // +prof+exec+file filename
|
std::string m_profExecFilename; // +prof+exec+file filename
|
||||||
std::string m_profVltFilename; // +prof+vlt filename
|
std::string m_profVltFilename; // +prof+vlt filename
|
||||||
|
std::string m_solverProgram; // SMT solver program
|
||||||
VlOs::DeltaCpuTime m_cpuTimeStart{false}; // CPU time, starts when create first model
|
VlOs::DeltaCpuTime m_cpuTimeStart{false}; // CPU time, starts when create first model
|
||||||
VlOs::DeltaWallTime m_wallTimeStart{false}; // Wall time, starts when create first model
|
VlOs::DeltaWallTime m_wallTimeStart{false}; // Wall time, starts when create first model
|
||||||
std::vector<traceBaseModelCb_t> m_traceBaseModelCbs; // Callbacks to traceRegisterModel
|
std::vector<traceBaseModelCb_t> m_traceBaseModelCbs; // Callbacks to traceRegisterModel
|
||||||
@@ -447,14 +474,23 @@ public:
|
|||||||
|
|
||||||
// METHODS - User called
|
// METHODS - User called
|
||||||
|
|
||||||
/// Enable assertions
|
|
||||||
void assertOn(bool flag) VL_MT_SAFE;
|
|
||||||
/// Return if assertions enabled
|
/// Return if assertions enabled
|
||||||
bool assertOn() const VL_MT_SAFE { return m_s.m_assertOn; }
|
bool assertOn() const VL_MT_SAFE;
|
||||||
/// Enable calculation of unused signals (for traces)
|
/// Enable all assertion types
|
||||||
void calcUnusedSigs(bool flag) VL_MT_SAFE;
|
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)
|
/// Return if calculating of unused signals (for traces)
|
||||||
bool calcUnusedSigs() const VL_MT_SAFE { return m_s.m_calcUnusedSigs; }
|
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,
|
/// Record command-line arguments, for retrieval by $test$plusargs/$value$plusargs,
|
||||||
/// and for parsing +verilator+ run-time arguments.
|
/// and for parsing +verilator+ run-time arguments.
|
||||||
/// This should be called before the first model is created.
|
/// This should be called before the first model is created.
|
||||||
@@ -469,52 +505,51 @@ public:
|
|||||||
/// Return VerilatedCovContext, allocate if needed
|
/// Return VerilatedCovContext, allocate if needed
|
||||||
/// Note if get unresolved reference then likely forgot to link verilated_cov.cpp
|
/// Note if get unresolved reference then likely forgot to link verilated_cov.cpp
|
||||||
VerilatedCovContext* coveragep() VL_MT_SAFE;
|
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
|
/// Debug is currently global, but for forward compatibility have a per-context method
|
||||||
static inline void debug(int val) VL_MT_SAFE;
|
static inline void debug(int val) VL_MT_SAFE;
|
||||||
/// Return debug level
|
/// Return current number of errors/assertions
|
||||||
static inline int debug() VL_MT_SAFE;
|
int errorCount() const VL_MT_SAFE { return m_s.m_errorCount; }
|
||||||
/// Set current number of errors/assertions
|
/// Set current number of errors/assertions
|
||||||
void errorCount(int val) VL_MT_SAFE;
|
void errorCount(int val) VL_MT_SAFE;
|
||||||
/// Increment current number of errors/assertions
|
/// Increment current number of errors/assertions
|
||||||
void errorCountInc() VL_MT_SAFE;
|
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
|
/// Return number of errors/assertions before stop
|
||||||
int errorLimit() const VL_MT_SAFE { return m_s.m_errorLimit; }
|
int errorLimit() const VL_MT_SAFE { return m_s.m_errorLimit; }
|
||||||
/// Set to throw fatal error on $stop/non-fatal error
|
/// Set number of errors/assertions before stop
|
||||||
void fatalOnError(bool flag) VL_MT_SAFE;
|
void errorLimit(int val) VL_MT_SAFE;
|
||||||
/// Return if to throw fatal error on $stop/non-fatal
|
/// Return if to throw fatal error on $stop/non-fatal
|
||||||
bool fatalOnError() const VL_MT_SAFE { return m_s.m_fatalOnError; }
|
bool fatalOnError() const VL_MT_SAFE { return m_s.m_fatalOnError; }
|
||||||
/// Set to throw fatal error on VPI errors
|
/// Set to throw fatal error on $stop/non-fatal error
|
||||||
void fatalOnVpiError(bool flag) VL_MT_SAFE;
|
void fatalOnError(bool flag) VL_MT_SAFE;
|
||||||
/// Return if to throw fatal error on VPI errors
|
/// Return if to throw fatal error on VPI errors
|
||||||
bool fatalOnVpiError() const VL_MT_SAFE { return m_s.m_fatalOnVpiError; }
|
bool fatalOnVpiError() const VL_MT_SAFE { return m_s.m_fatalOnVpiError; }
|
||||||
/// Set if got a $stop or non-fatal error
|
/// Set to throw fatal error on VPI errors
|
||||||
void gotError(bool flag) VL_MT_SAFE;
|
void fatalOnVpiError(bool flag) VL_MT_SAFE;
|
||||||
/// Return if got a $stop or non-fatal error
|
/// Return if got a $stop or non-fatal error
|
||||||
bool gotError() const VL_MT_SAFE { return m_s.m_gotError; }
|
bool gotError() const VL_MT_SAFE { return m_s.m_gotError; }
|
||||||
/// Set if got a $finish or $stop/error
|
/// Set if got a $stop or non-fatal error
|
||||||
void gotFinish(bool flag) VL_MT_SAFE;
|
void gotError(bool flag) VL_MT_SAFE;
|
||||||
/// Return if got a $finish or $stop/error
|
/// Return if got a $finish or $stop/error
|
||||||
bool gotFinish() const VL_MT_SAFE { return m_s.m_gotFinish; }
|
bool gotFinish() const VL_MT_SAFE { return m_s.m_gotFinish; }
|
||||||
/// Enable quiet (also prevents need for OS calls to get CPU time)
|
/// Set if got a $finish or $stop/error
|
||||||
void quiet(bool flag) VL_MT_SAFE;
|
void gotFinish(bool flag) VL_MT_SAFE;
|
||||||
/// Return if quiet enabled
|
/// Return if quiet enabled
|
||||||
bool quiet() const VL_MT_SAFE { return m_s.m_quiet; }
|
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.
|
/// Select initial value of otherwise uninitialized signals.
|
||||||
/// 0 = Set to zeros
|
/// 0 = Set to zeros
|
||||||
/// 1 = Set all bits to one
|
/// 1 = Set all bits to one
|
||||||
/// 2 = Randomize all bits
|
/// 2 = Randomize all bits
|
||||||
void randReset(int val) VL_MT_SAFE;
|
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
|
/// Set default random seed, 0 = seed it automatically
|
||||||
int randSeed() const VL_MT_SAFE { return m_s.m_randSeed; }
|
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
|
/// Return statistic: CPU time delta from model created until now
|
||||||
double statCpuTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex);
|
double statCpuTimeSinceStart() const VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
@@ -606,23 +641,27 @@ public:
|
|||||||
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
|
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
|
||||||
|
|
||||||
// Internal: coverage
|
// Internal: coverage
|
||||||
void coverageFilename(const std::string& flag) VL_MT_SAFE;
|
|
||||||
std::string coverageFilename() const VL_MT_SAFE;
|
std::string coverageFilename() const VL_MT_SAFE;
|
||||||
|
void coverageFilename(const std::string& flag) VL_MT_SAFE;
|
||||||
|
|
||||||
// Internal: $dumpfile
|
// Internal: $dumpfile
|
||||||
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
|
||||||
std::string dumpfile() const 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);
|
std::string dumpfileCheck() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||||
|
|
||||||
// Internal: --prof-exec related settings
|
// 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; }
|
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; }
|
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;
|
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;
|
std::string profVltFilename() const VL_MT_SAFE;
|
||||||
|
void profVltFilename(const std::string& flag) VL_MT_SAFE;
|
||||||
|
|
||||||
|
// Internal: SMT solver program
|
||||||
|
std::string solverProgram() const VL_MT_SAFE;
|
||||||
|
void solverProgram(const std::string& flag) VL_MT_SAFE;
|
||||||
|
|
||||||
// Internal: Find scope
|
// Internal: Find scope
|
||||||
const VerilatedScope* scopeFind(const char* namep) const VL_MT_SAFE;
|
const VerilatedScope* scopeFind(const char* namep) const VL_MT_SAFE;
|
||||||
@@ -757,8 +796,6 @@ class Verilated final {
|
|||||||
public:
|
public:
|
||||||
// METHODS - User called
|
// METHODS - User called
|
||||||
|
|
||||||
/// Enable debug of internal verilated code
|
|
||||||
static void debug(int level) VL_MT_SAFE;
|
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
/// Return debug level
|
/// Return debug level
|
||||||
/// When multithreaded this may not immediately react to another thread
|
/// When multithreaded this may not immediately react to another thread
|
||||||
@@ -768,6 +805,8 @@ public:
|
|||||||
/// Return constant 0 debug level, so C++'s optimizer rips up
|
/// Return constant 0 debug level, so C++'s optimizer rips up
|
||||||
static constexpr int debug() VL_PURE { return 0; }
|
static constexpr int debug() VL_PURE { return 0; }
|
||||||
#endif
|
#endif
|
||||||
|
/// Enable debug of internal verilated code
|
||||||
|
static void debug(int level) VL_MT_SAFE;
|
||||||
|
|
||||||
/// Set the last VerilatedContext accessed
|
/// Set the last VerilatedContext accessed
|
||||||
/// Generally threadContextp(value) should be called instead
|
/// Generally threadContextp(value) should be called instead
|
||||||
@@ -799,18 +838,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef VL_NO_LEGACY
|
#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
|
/// Return VerilatedContext::assertOn() using current thread's VerilatedContext
|
||||||
static bool assertOn() VL_MT_SAFE { return Verilated::threadContextp()->assertOn(); }
|
static bool assertOn() VL_MT_SAFE { return Verilated::threadContextp()->assertOn(); }
|
||||||
/// Call VerilatedContext::calcUnusedSigs using current thread's VerilatedContext
|
/// Call VerilatedContext::assertOn using current thread's VerilatedContext
|
||||||
static void calcUnusedSigs(bool flag) VL_MT_SAFE {
|
static void assertOn(bool flag) VL_MT_SAFE { Verilated::threadContextp()->assertOn(flag); }
|
||||||
Verilated::threadContextp()->calcUnusedSigs(flag);
|
|
||||||
}
|
|
||||||
/// Return VerilatedContext::calcUnusedSigs using current thread's VerilatedContext
|
/// Return VerilatedContext::calcUnusedSigs using current thread's VerilatedContext
|
||||||
static bool calcUnusedSigs() VL_MT_SAFE {
|
static bool calcUnusedSigs() VL_MT_SAFE {
|
||||||
return Verilated::threadContextp()->calcUnusedSigs();
|
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
|
/// Call VerilatedContext::commandArgs using current thread's VerilatedContext
|
||||||
static void commandArgs(int argc, const char** argv) VL_MT_SAFE {
|
static void commandArgs(int argc, const char** argv) VL_MT_SAFE {
|
||||||
Verilated::threadContextp()->commandArgs(argc, argv);
|
Verilated::threadContextp()->commandArgs(argc, argv);
|
||||||
@@ -826,44 +865,44 @@ public:
|
|||||||
static const char* commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
|
static const char* commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE {
|
||||||
return Verilated::threadContextp()->commandArgsPlusMatch(prefixp);
|
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
|
/// Return VerilatedContext::errorLimit using current thread's VerilatedContext
|
||||||
static int errorLimit() VL_MT_SAFE { return Verilated::threadContextp()->errorLimit(); }
|
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
|
/// Call VerilatedContext::fatalOnError using current thread's VerilatedContext
|
||||||
static void fatalOnError(bool flag) VL_MT_SAFE {
|
static void fatalOnError(bool flag) VL_MT_SAFE {
|
||||||
Verilated::threadContextp()->fatalOnError(flag);
|
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
|
/// Return VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
|
||||||
static bool fatalOnVpiError() VL_MT_SAFE {
|
static bool fatalOnVpiError() VL_MT_SAFE {
|
||||||
return Verilated::threadContextp()->fatalOnVpiError();
|
return Verilated::threadContextp()->fatalOnVpiError();
|
||||||
}
|
}
|
||||||
/// Call VerilatedContext::gotError using current thread's VerilatedContext
|
/// Call VerilatedContext::fatalOnVpiError using current thread's VerilatedContext
|
||||||
static void gotError(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotError(flag); }
|
static void fatalOnVpiError(bool flag) VL_MT_SAFE {
|
||||||
|
Verilated::threadContextp()->fatalOnVpiError(flag);
|
||||||
|
}
|
||||||
/// Return VerilatedContext::gotError using current thread's VerilatedContext
|
/// Return VerilatedContext::gotError using current thread's VerilatedContext
|
||||||
static bool gotError() VL_MT_SAFE { return Verilated::threadContextp()->gotError(); }
|
static bool gotError() VL_MT_SAFE { return Verilated::threadContextp()->gotError(); }
|
||||||
/// Call VerilatedContext::gotFinish using current thread's VerilatedContext
|
/// Call VerilatedContext::gotError using current thread's VerilatedContext
|
||||||
static void gotFinish(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotFinish(flag); }
|
static void gotError(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotError(flag); }
|
||||||
/// Return VerilatedContext::gotFinish using current thread's VerilatedContext
|
/// Return VerilatedContext::gotFinish using current thread's VerilatedContext
|
||||||
static bool gotFinish() VL_MT_SAFE { return Verilated::threadContextp()->gotFinish(); }
|
static bool gotFinish() VL_MT_SAFE { return Verilated::threadContextp()->gotFinish(); }
|
||||||
/// Call VerilatedContext::randReset using current thread's VerilatedContext
|
/// Call VerilatedContext::gotFinish using current thread's VerilatedContext
|
||||||
static void randReset(int val) VL_MT_SAFE { Verilated::threadContextp()->randReset(val); }
|
static void gotFinish(bool flag) VL_MT_SAFE { Verilated::threadContextp()->gotFinish(flag); }
|
||||||
/// Return VerilatedContext::randReset using current thread's VerilatedContext
|
/// Return VerilatedContext::randReset using current thread's VerilatedContext
|
||||||
static int randReset() VL_MT_SAFE { return Verilated::threadContextp()->randReset(); }
|
static int randReset() VL_MT_SAFE { return Verilated::threadContextp()->randReset(); }
|
||||||
/// Call VerilatedContext::randSeed using current thread's VerilatedContext
|
/// Call VerilatedContext::randReset using current thread's VerilatedContext
|
||||||
static void randSeed(int val) VL_MT_SAFE { Verilated::threadContextp()->randSeed(val); }
|
static void randReset(int val) VL_MT_SAFE { Verilated::threadContextp()->randReset(val); }
|
||||||
/// Return VerilatedContext::randSeed using current thread's VerilatedContext
|
/// Return VerilatedContext::randSeed using current thread's VerilatedContext
|
||||||
static int randSeed() VL_MT_SAFE { return Verilated::threadContextp()->randSeed(); }
|
static int randSeed() VL_MT_SAFE { return Verilated::threadContextp()->randSeed(); }
|
||||||
/// Call VerilatedContext::time using current thread's VerilatedContext
|
/// Call VerilatedContext::randSeed using current thread's VerilatedContext
|
||||||
static void time(uint64_t val) VL_MT_SAFE { Verilated::threadContextp()->time(val); }
|
static void randSeed(int val) VL_MT_SAFE { Verilated::threadContextp()->randSeed(val); }
|
||||||
/// Return VerilatedContext::time using current thread's VerilatedContext
|
/// Return VerilatedContext::time using current thread's VerilatedContext
|
||||||
static uint64_t time() VL_MT_SAFE { return Verilated::threadContextp()->time(); }
|
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
|
/// Call VerilatedContext::timeInc using current thread's VerilatedContext
|
||||||
static void timeInc(uint64_t add) VL_MT_UNSAFE { Verilated::threadContextp()->timeInc(add); }
|
static void timeInc(uint64_t add) VL_MT_UNSAFE { Verilated::threadContextp()->timeInc(add); }
|
||||||
// Deprecated
|
// Deprecated
|
||||||
@@ -953,8 +992,8 @@ public:
|
|||||||
|
|
||||||
// Internal: Set the mtaskId, called when an mtask starts
|
// Internal: Set the mtaskId, called when an mtask starts
|
||||||
// Per thread, so no need to be in VerilatedContext
|
// 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 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 endOfEvalReqdInc() VL_MT_SAFE { ++t_s.t_endOfEvalReqd; }
|
||||||
static void endOfEvalReqdDec() 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 \
|
-I$(VERILATOR_ROOT)/include/vltstd \
|
||||||
-DVM_COVERAGE=$(VM_COVERAGE) \
|
-DVM_COVERAGE=$(VM_COVERAGE) \
|
||||||
-DVM_SC=$(VM_SC) \
|
-DVM_SC=$(VM_SC) \
|
||||||
|
-DVM_TIMING=$(VM_TIMING) \
|
||||||
-DVM_TRACE=$(VM_TRACE) \
|
-DVM_TRACE=$(VM_TRACE) \
|
||||||
-DVM_TRACE_FST=$(VM_TRACE_FST) \
|
-DVM_TRACE_FST=$(VM_TRACE_FST) \
|
||||||
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \
|
-DVM_TRACE_VCD=$(VM_TRACE_VCD) \
|
||||||
@@ -225,7 +226,6 @@ endif
|
|||||||
# 1. Extract object files from .a
|
# 1. Extract object files from .a
|
||||||
# 2. Create a new archive from extracted .o and given .o
|
# 2. Create a new archive from extracted .o and given .o
|
||||||
%.a: | %.verilator_deplist.tmp
|
%.a: | %.verilator_deplist.tmp
|
||||||
$(info Archive $(AR) -rcs $@ $^)
|
|
||||||
$(foreach L, $(filter-out %.a,$^), $(shell echo $L >>[email protected]_deplist.tmp))
|
$(foreach L, $(filter-out %.a,$^), $(shell echo $L >>[email protected]_deplist.tmp))
|
||||||
@if test $(words $(filter %.a,$^)) -eq 0; then \
|
@if test $(words $(filter %.a,$^)) -eq 0; then \
|
||||||
$(RM) -f $@; \
|
$(RM) -f $@; \
|
||||||
|
|||||||
@@ -93,8 +93,8 @@ public:
|
|||||||
/// Make all data per_instance, overriding point's per_instance
|
/// Make all data per_instance, overriding point's per_instance
|
||||||
void forcePerInstance(bool flag) VL_MT_SAFE;
|
void forcePerInstance(bool flag) VL_MT_SAFE;
|
||||||
/// Write all coverage data to a file
|
/// 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() VL_MT_SAFE { write(defaultFilename()); }
|
||||||
|
void write(const std::string& filename) VL_MT_SAFE;
|
||||||
/// Clear coverage points (and call delete on all items)
|
/// Clear coverage points (and call delete on all items)
|
||||||
void clear() VL_MT_SAFE;
|
void clear() VL_MT_SAFE;
|
||||||
/// Clear items not matching the provided string
|
/// Clear items not matching the provided string
|
||||||
@@ -165,8 +165,8 @@ public:
|
|||||||
/// Return default filename for the current thread
|
/// Return default filename for the current thread
|
||||||
static std::string defaultFilename() VL_MT_SAFE { return threadCovp()->defaultFilename(); }
|
static std::string defaultFilename() VL_MT_SAFE { return threadCovp()->defaultFilename(); }
|
||||||
/// Write all coverage data to a file for the current thread
|
/// 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() 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
|
/// Clear coverage points (and call delete on all items) for the current thread
|
||||||
static void clear() VL_MT_SAFE { threadCovp()->clear(); }
|
static void clear() VL_MT_SAFE { threadCovp()->clear(); }
|
||||||
/// Clear items not matching the provided string for the current thread
|
/// 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
|
// TODO: should return std::optional<fstScopeType>, but I can't have C++17
|
||||||
static std::pair<bool, fstScopeType> toFstScopeType(VerilatedTracePrefixType type) {
|
static std::pair<bool, fstScopeType> toFstScopeType(VerilatedTracePrefixType type) {
|
||||||
switch (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_MODULE: return {true, FST_ST_VCD_MODULE};
|
||||||
case VerilatedTracePrefixType::SCOPE_INTERFACE: return {true, FST_ST_VCD_INTERFACE};
|
case VerilatedTracePrefixType::SCOPE_INTERFACE: return {true, FST_ST_VCD_INTERFACE};
|
||||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
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) {
|
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 auto pair = toFstScopeType(type);
|
||||||
const bool properScope = pair.first;
|
const bool properScope = pair.first;
|
||||||
const fstScopeType scopeType = pair.second;
|
const fstScopeType scopeType = pair.second;
|
||||||
@@ -149,10 +163,11 @@ void VerilatedFst::pushPrefix(const std::string& name, VerilatedTracePrefixType
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedFst::popPrefix() {
|
void VerilatedFst::popPrefix() {
|
||||||
|
assert(!m_prefixStack.empty());
|
||||||
const bool properScope = toFstScopeType(m_prefixStack.back().second).first;
|
const bool properScope = toFstScopeType(m_prefixStack.back().second).first;
|
||||||
if (properScope) fstWriterSetUpscope(m_fst);
|
if (properScope) fstWriterSetUpscope(m_fst);
|
||||||
m_prefixStack.pop_back();
|
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,
|
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.
|
// so always inline them.
|
||||||
|
|
||||||
VL_ATTR_ALWINLINE
|
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]););
|
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
|
||||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
|
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ private:
|
|||||||
friend VerilatedFstBuffer; // Give the buffer access to the private bits
|
friend VerilatedFstBuffer; // Give the buffer access to the private bits
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// FST specific internals
|
// FST-specific internals
|
||||||
|
|
||||||
void* m_fst = nullptr;
|
void* m_fst = nullptr;
|
||||||
std::map<uint32_t, vlFstHandle> m_code2symbol;
|
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
|
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||||
// called from only one place (the full* methods), so always inline them.
|
// 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 emitBit(uint32_t code, CData newval);
|
||||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||||
|
|||||||
+361
-35
@@ -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
|
/// Routine to call for $stop and non-fatal error
|
||||||
/// User code may wish to replace this function, to do so, define VL_USER_STOP.
|
/// User code may wish to replace this function, to do so, define VL_USER_STOP.
|
||||||
/// This code does not have to be thread safe.
|
/// 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;
|
extern void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE;
|
||||||
|
|
||||||
/// Routine to call for fatal messages
|
/// Routine to call for fatal messages
|
||||||
/// User code may wish to replace this function, to do so, define VL_USER_FATAL.
|
/// User code may wish to replace this function, to do so, define VL_USER_FATAL.
|
||||||
/// This code does not have to be thread safe.
|
/// 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,
|
extern void vl_fatal(const char* filename, int linenum, const char* hier,
|
||||||
const char* msg) VL_MT_UNSAFE;
|
const char* msg) VL_MT_UNSAFE;
|
||||||
|
|
||||||
/// Routine to call for warning messages
|
/// Routine to call for warning messages
|
||||||
/// User code may wish to replace this function, to do so, define VL_USER_WARN.
|
/// User code may wish to replace this function, to do so, define VL_USER_WARN.
|
||||||
/// This code does not have to be thread safe.
|
/// 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,
|
extern void vl_warn(const char* filename, int linenum, const char* hier,
|
||||||
const char* msg) VL_MT_UNSAFE;
|
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;
|
extern QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE;
|
||||||
/// Random reset a signal of given width (init time only)
|
/// Random reset a signal of given width (init time only)
|
||||||
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
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)
|
/// Zero reset a signal (slow - else use VL_ZERO_W)
|
||||||
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||||
|
|
||||||
@@ -115,6 +124,9 @@ extern void VL_PRINTTIMESCALE(const char* namep, const char* timeunitp,
|
|||||||
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP const lwp, WDataInP const rwp,
|
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP const lwp, WDataInP const rwp,
|
||||||
bool is_modulus) VL_MT_SAFE;
|
bool is_modulus) VL_MT_SAFE;
|
||||||
|
|
||||||
|
extern void _vl_vsss_based(WDataOutP owp, int obits, int baseLog2, const char* strp,
|
||||||
|
size_t posstart, size_t posend) VL_MT_SAFE;
|
||||||
|
|
||||||
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE;
|
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE;
|
||||||
|
|
||||||
extern void VL_FFLUSH_I(IData fdi) VL_MT_SAFE;
|
extern void VL_FFLUSH_I(IData fdi) VL_MT_SAFE;
|
||||||
@@ -152,6 +164,7 @@ extern std::string VL_STACKTRACE_N() VL_MT_SAFE;
|
|||||||
extern IData VL_SYSTEM_IW(int lhswords, WDataInP const lhsp) VL_MT_SAFE;
|
extern IData VL_SYSTEM_IW(int lhswords, WDataInP const lhsp) VL_MT_SAFE;
|
||||||
extern IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE;
|
extern IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE;
|
||||||
inline IData VL_SYSTEM_II(IData lhs) VL_MT_SAFE { return VL_SYSTEM_IQ(lhs); }
|
inline IData VL_SYSTEM_II(IData lhs) VL_MT_SAFE { return VL_SYSTEM_IQ(lhs); }
|
||||||
|
extern IData VL_SYSTEM_IN(const std::string& lhs) VL_MT_SAFE;
|
||||||
|
|
||||||
extern IData VL_TESTPLUSARGS_I(const std::string& format) VL_MT_SAFE;
|
extern IData VL_TESTPLUSARGS_I(const std::string& format) VL_MT_SAFE;
|
||||||
extern const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE; // PLIish
|
extern const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE; // PLIish
|
||||||
@@ -215,6 +228,10 @@ static inline QData VL_CVT_Q_D(double lhs) VL_PURE {
|
|||||||
return u.q;
|
return u.q;
|
||||||
}
|
}
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
// Return string from DPI char*
|
||||||
|
static inline std::string VL_CVT_N_CSTR(const char* lhsp) VL_PURE {
|
||||||
|
return lhsp ? std::string{lhsp} : ""s;
|
||||||
|
}
|
||||||
|
|
||||||
// Return double from lhs (numeric) unsigned
|
// Return double from lhs (numeric) unsigned
|
||||||
double VL_ITOR_D_W(int lbits, WDataInP const lwp) VL_PURE;
|
double VL_ITOR_D_W(int lbits, WDataInP const lwp) VL_PURE;
|
||||||
@@ -238,7 +255,7 @@ static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_MT_SAFE {
|
|||||||
VL_SET_WQ(lwp, lhs);
|
VL_SET_WQ(lwp, lhs);
|
||||||
return VL_ISTOR_D_W(lbits, lwp);
|
return VL_ISTOR_D_W(lbits, lwp);
|
||||||
}
|
}
|
||||||
// Return QData from double (numeric)
|
// Return IData truncated from double (numeric)
|
||||||
static inline IData VL_RTOI_I_D(double lhs) VL_PURE { return static_cast<int32_t>(VL_TRUNC(lhs)); }
|
static inline IData VL_RTOI_I_D(double lhs) VL_PURE { return static_cast<int32_t>(VL_TRUNC(lhs)); }
|
||||||
|
|
||||||
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
|
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
|
||||||
@@ -504,19 +521,18 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
|
|||||||
{ (svar).write(rd); }
|
{ (svar).write(rd); }
|
||||||
#define VL_ASSIGN_SBQ(obits, svar, rd) \
|
#define VL_ASSIGN_SBQ(obits, svar, rd) \
|
||||||
{ (svar).write(rd); }
|
{ (svar).write(rd); }
|
||||||
#define VL_SC_BITS_PER_DIGIT 30 // This comes from sc_nbdefs.h BITS_PER_DIGIT
|
|
||||||
#define VL_ASSIGN_SBW(obits, svar, rwp) \
|
#define VL_ASSIGN_SBW(obits, svar, rwp) \
|
||||||
{ \
|
{ \
|
||||||
sc_dt::sc_biguint<(obits)> _butemp; \
|
sc_dt::sc_biguint<(obits)> _butemp; \
|
||||||
int32_t lsb = 0; \
|
int32_t lsb = 0; \
|
||||||
uint32_t* chunkp = _butemp.get_raw(); \
|
uint32_t* chunkp = _butemp.get_raw(); \
|
||||||
while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \
|
while (lsb + BITS_PER_DIGIT < (obits)) { \
|
||||||
static_assert(std::is_same<IData, EData>::value, "IData and EData mismatch"); \
|
static_assert(std::is_same<IData, EData>::value, "IData and EData mismatch"); \
|
||||||
const uint32_t data = VL_SEL_IWII(lsb + VL_SC_BITS_PER_DIGIT + 1, (rwp).data(), lsb, \
|
const uint32_t data \
|
||||||
VL_SC_BITS_PER_DIGIT); \
|
= VL_SEL_IWII(lsb + BITS_PER_DIGIT + 1, (rwp).data(), lsb, BITS_PER_DIGIT); \
|
||||||
*chunkp = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \
|
*chunkp = data & VL_MASK_E(BITS_PER_DIGIT); \
|
||||||
++chunkp; \
|
++chunkp; \
|
||||||
lsb += VL_SC_BITS_PER_DIGIT; \
|
lsb += BITS_PER_DIGIT; \
|
||||||
} \
|
} \
|
||||||
if (lsb < (obits)) { \
|
if (lsb < (obits)) { \
|
||||||
const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \
|
const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \
|
||||||
@@ -1570,49 +1586,184 @@ static inline WDataOutP VL_STREAML_WWI(int lbits, WDataOutP owp, WDataInP const
|
|||||||
return owp;
|
return owp;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
static inline IData VL_PACK_II(int obits, int lbits, const VlQueue<CData>& q) {
|
||||||
static inline void VL_ASSIGN_DYN_Q(VlQueue<T>& q, int elem_size, int lbits, QData from) {
|
IData ret = 0;
|
||||||
const int size = (lbits + elem_size - 1) / elem_size;
|
for (size_t i = 0; i < q.size(); ++i) ret |= static_cast<IData>(q.at(i)) << (i * lbits);
|
||||||
q.renew(size);
|
return ret;
|
||||||
const QData mask = VL_MASK_Q(elem_size);
|
|
||||||
for (int i = 0; i < size; ++i) q.at(i) = (T)((from >> (i * elem_size)) & mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t T_Depth>
|
static inline IData VL_PACK_II(int obits, int lbits, const VlQueue<SData>& q) {
|
||||||
static inline void VL_ASSIGN_UNPACK_Q(VlUnpacked<T, T_Depth>& q, size_t elem_size, QData from) {
|
IData ret = 0;
|
||||||
const QData mask = VL_MASK_Q(elem_size);
|
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)
|
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>
|
template <std::size_t T_Depth>
|
||||||
static inline IData VL_DYN_TO_I(const VlQueue<T>& q, int elem_size) {
|
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<SData, T_Depth>& q) {
|
||||||
IData ret = 0;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <std::size_t T_Depth>
|
||||||
static inline QData VL_DYN_TO_Q(const VlQueue<T>& q, int elem_size) {
|
static inline IData VL_PACK_II(int obits, int lbits, const VlUnpacked<IData, T_Depth>& q) {
|
||||||
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) {
|
|
||||||
IData ret = 0;
|
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;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, std::size_t T_Depth>
|
static inline QData VL_PACK_QI(int obits, int lbits, const VlQueue<CData>& q) {
|
||||||
static inline QData VL_UNPACK_TO_Q(const VlUnpacked<T, T_Depth>& q, size_t elem_size) {
|
|
||||||
QData ret = 0;
|
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;
|
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.
|
// 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.
|
// 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.
|
// Note the bit shifts are always constants, so the adds in these constify out.
|
||||||
@@ -2052,6 +2203,181 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataIn
|
|||||||
//======================================================================
|
//======================================================================
|
||||||
// Expressions needing insert/select
|
// 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)
|
// Return QData from double (numeric)
|
||||||
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
|
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
|
||||||
static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {
|
static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {
|
||||||
|
|||||||
@@ -12,13 +12,13 @@
|
|||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
///
|
///
|
||||||
/// \file
|
/// \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.
|
/// 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
|
/// 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.
|
/// of instruction sets, and a common mechanism to disable them.
|
||||||
///
|
///
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|||||||
@@ -0,0 +1,506 @@
|
|||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Code available from: https://verilator.org
|
||||||
|
//
|
||||||
|
// Copyright 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
|
||||||
|
//
|
||||||
|
//=========================================================================
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilated randomization implementation code
|
||||||
|
///
|
||||||
|
/// This file must be compiled and linked against all Verilated objects
|
||||||
|
/// that use randomization features.
|
||||||
|
///
|
||||||
|
/// See the internals documentation docs/internals.rst for details.
|
||||||
|
///
|
||||||
|
//=========================================================================
|
||||||
|
|
||||||
|
#include "verilated_random.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <sstream>
|
||||||
|
#include <streambuf>
|
||||||
|
|
||||||
|
#define _VL_SOLVER_HASH_LEN 1
|
||||||
|
#define _VL_SOLVER_HASH_LEN_TOTAL 4
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
|
||||||
|
# define _VL_SOLVER_PIPE // Allow pipe SMT solving. Needs fork()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef _VL_SOLVER_PIPE
|
||||||
|
# include <sys/wait.h>
|
||||||
|
# include <fcntl.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(_WIN32) || defined(__MINGW32__)
|
||||||
|
# include <io.h> // open, read, write, close
|
||||||
|
#endif
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
class Process final : private std::streambuf, public std::iostream {
|
||||||
|
static constexpr int BUFFER_SIZE = 4096;
|
||||||
|
const char* const* m_cmd = nullptr; // fork() process argv
|
||||||
|
#ifdef _VL_SOLVER_PIPE
|
||||||
|
pid_t m_pid = 0; // fork() process id
|
||||||
|
#else
|
||||||
|
int m_pid = 0; // fork() process id - always zero as disabled
|
||||||
|
#endif
|
||||||
|
bool m_pidExited = true; // If subprocess has exited and can be opened
|
||||||
|
int m_pidStatus = 0; // fork() process exit status, valid if m_pidExited
|
||||||
|
int m_writeFd = -1; // File descriptor TO subprocess
|
||||||
|
int m_readFd = -1; // File descriptor FROM subprocess
|
||||||
|
char m_readBuf[BUFFER_SIZE];
|
||||||
|
char m_writeBuf[BUFFER_SIZE];
|
||||||
|
|
||||||
|
public:
|
||||||
|
typedef std::streambuf::traits_type traits_type;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int overflow(int c = traits_type::eof()) override {
|
||||||
|
char c2 = static_cast<char>(c);
|
||||||
|
if (pbase() == pptr()) return 0;
|
||||||
|
size_t size = pptr() - pbase();
|
||||||
|
ssize_t n = ::write(m_writeFd, pbase(), size);
|
||||||
|
if (n == -1) perror("write");
|
||||||
|
if (n <= 0) {
|
||||||
|
wait_report();
|
||||||
|
return traits_type::eof();
|
||||||
|
}
|
||||||
|
if (n == size)
|
||||||
|
setp(m_writeBuf, m_writeBuf + sizeof(m_writeBuf));
|
||||||
|
else
|
||||||
|
setp(m_writeBuf + n, m_writeBuf + sizeof(m_writeBuf));
|
||||||
|
if (c != traits_type::eof()) sputc(c2);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
int underflow() override {
|
||||||
|
sync();
|
||||||
|
ssize_t n = ::read(m_readFd, m_readBuf, sizeof(m_readBuf));
|
||||||
|
if (n == -1) perror("read");
|
||||||
|
if (n <= 0) {
|
||||||
|
wait_report();
|
||||||
|
return traits_type::eof();
|
||||||
|
}
|
||||||
|
setg(m_readBuf, m_readBuf, m_readBuf + n);
|
||||||
|
return traits_type::to_int_type(m_readBuf[0]);
|
||||||
|
}
|
||||||
|
int sync() override {
|
||||||
|
overflow();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit Process(const char* const* const cmd = nullptr)
|
||||||
|
: std::streambuf{}
|
||||||
|
, std::iostream{this}
|
||||||
|
, m_cmd{cmd} {
|
||||||
|
open(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wait_report() {
|
||||||
|
if (m_pidExited) return;
|
||||||
|
#ifdef _VL_SOLVER_PIPE
|
||||||
|
if (waitpid(m_pid, &m_pidStatus, 0) != m_pid) return;
|
||||||
|
if (m_pidStatus) {
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "Subprocess command `" << m_cmd[0];
|
||||||
|
for (const char* const* arg = m_cmd + 1; *arg; arg++) msg << ' ' << *arg;
|
||||||
|
msg << "' failed: ";
|
||||||
|
if (WIFSIGNALED(m_pidStatus))
|
||||||
|
msg << strsignal(WTERMSIG(m_pidStatus))
|
||||||
|
<< (WCOREDUMP(m_pidStatus) ? " (core dumped)" : "");
|
||||||
|
else if (WIFEXITED(m_pidStatus))
|
||||||
|
msg << "exit status " << WEXITSTATUS(m_pidStatus);
|
||||||
|
const std::string str = msg.str();
|
||||||
|
VL_WARN_MT("", 0, "Process", str.c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
m_pidExited = true;
|
||||||
|
m_pid = 0;
|
||||||
|
closeFds();
|
||||||
|
}
|
||||||
|
|
||||||
|
void closeFds() {
|
||||||
|
if (m_writeFd != -1) {
|
||||||
|
close(m_writeFd);
|
||||||
|
m_writeFd = -1;
|
||||||
|
}
|
||||||
|
if (m_readFd != -1) {
|
||||||
|
close(m_readFd);
|
||||||
|
m_readFd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool open(const char* const* const cmd) {
|
||||||
|
setp(std::begin(m_writeBuf), std::end(m_writeBuf));
|
||||||
|
setg(m_readBuf, m_readBuf, m_readBuf);
|
||||||
|
#ifdef _VL_SOLVER_PIPE
|
||||||
|
if (!cmd || !cmd[0]) return false;
|
||||||
|
m_cmd = cmd;
|
||||||
|
int fd_stdin[2]; // Can't use std::array
|
||||||
|
int fd_stdout[2]; // Can't use std::array
|
||||||
|
constexpr int P_RD = 0;
|
||||||
|
constexpr int P_WR = 1;
|
||||||
|
|
||||||
|
if (pipe(fd_stdin) != 0) {
|
||||||
|
perror("Process::open: pipe");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pipe(fd_stdout) != 0) {
|
||||||
|
perror("Process::open: pipe");
|
||||||
|
close(fd_stdin[P_RD]);
|
||||||
|
close(fd_stdin[P_WR]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fd_stdin[P_RD] <= 2 || fd_stdin[P_WR] <= 2 || fd_stdout[P_RD] <= 2
|
||||||
|
|| fd_stdout[P_WR] <= 2) {
|
||||||
|
// We'd have to rearrange all of the FD usages in this case.
|
||||||
|
// Too unlikely; verilator isn't a daemon.
|
||||||
|
fprintf(stderr, "stdin/stdout closed before pipe opened\n");
|
||||||
|
close(fd_stdin[P_RD]);
|
||||||
|
close(fd_stdin[P_WR]);
|
||||||
|
close(fd_stdout[P_RD]);
|
||||||
|
close(fd_stdout[P_WR]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pid_t pid = fork();
|
||||||
|
if (pid < 0) {
|
||||||
|
perror("Process::open: fork");
|
||||||
|
close(fd_stdin[P_RD]);
|
||||||
|
close(fd_stdin[P_WR]);
|
||||||
|
close(fd_stdout[P_RD]);
|
||||||
|
close(fd_stdout[P_WR]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (pid == 0) {
|
||||||
|
// Child
|
||||||
|
close(fd_stdin[P_WR]);
|
||||||
|
dup2(fd_stdin[P_RD], STDIN_FILENO);
|
||||||
|
close(fd_stdout[P_RD]);
|
||||||
|
dup2(fd_stdout[P_WR], STDOUT_FILENO);
|
||||||
|
execvp(cmd[0], const_cast<char* const*>(cmd));
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "Process::open: execvp(" << cmd[0] << ")";
|
||||||
|
const std::string str = msg.str();
|
||||||
|
perror(str.c_str());
|
||||||
|
_exit(127);
|
||||||
|
}
|
||||||
|
// Parent
|
||||||
|
m_pid = pid;
|
||||||
|
m_pidExited = false;
|
||||||
|
m_pidStatus = 0;
|
||||||
|
m_readFd = fd_stdout[P_RD];
|
||||||
|
m_writeFd = fd_stdin[P_WR];
|
||||||
|
|
||||||
|
close(fd_stdin[P_RD]);
|
||||||
|
close(fd_stdout[P_WR]);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static Process& getSolver() {
|
||||||
|
static Process s_solver;
|
||||||
|
static bool s_done = false;
|
||||||
|
if (s_done) return s_solver;
|
||||||
|
s_done = true;
|
||||||
|
|
||||||
|
static std::vector<const char*> s_argv;
|
||||||
|
static std::string s_program = Verilated::threadContextp()->solverProgram();
|
||||||
|
s_argv.emplace_back(&s_program[0]);
|
||||||
|
for (char* arg = &s_program[0]; *arg; arg++) {
|
||||||
|
if (*arg == ' ') {
|
||||||
|
*arg = '\0';
|
||||||
|
s_argv.emplace_back(arg + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
s_argv.emplace_back(nullptr);
|
||||||
|
|
||||||
|
const char* const* const cmd = &s_argv[0];
|
||||||
|
s_solver.open(cmd);
|
||||||
|
s_solver << "(set-logic QF_ABV)\n";
|
||||||
|
s_solver << "(check-sat)\n";
|
||||||
|
s_solver << "(reset)\n";
|
||||||
|
std::string s;
|
||||||
|
getline(s_solver, s);
|
||||||
|
if (s == "sat") return s_solver;
|
||||||
|
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "Unable to communicate with SAT solver, please check its installation or specify a "
|
||||||
|
"different one in VERILATOR_SOLVER environment variable.\n";
|
||||||
|
msg << " ... Tried: $";
|
||||||
|
for (const char* const* arg = cmd; *arg; arg++) msg << ' ' << *arg;
|
||||||
|
msg << '\n';
|
||||||
|
const std::string str = msg.str();
|
||||||
|
VL_WARN_MT("", 0, "randomize", str.c_str());
|
||||||
|
|
||||||
|
while (getline(s_solver, s)) {}
|
||||||
|
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::emitGetValue(std::ostream& s) const { s << ' ' << m_name; }
|
||||||
|
void VlRandomVar::emitExtract(std::ostream& s, int i) const {
|
||||||
|
s << " ((_ extract " << i << ' ' << i << ") " << m_name << ')';
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
switch (val[i++]) {
|
||||||
|
case 'b': _vl_vsss_based(owp, obits, 1, &val[i], 0, val.size() - i); break;
|
||||||
|
case 'o': _vl_vsss_based(owp, obits, 3, &val[i], 0, val.size() - i); break;
|
||||||
|
case 'h': // FALLTHRU
|
||||||
|
case 'x': _vl_vsss_based(owp, obits, 4, &val[i], 0, val.size() - i); break;
|
||||||
|
default:
|
||||||
|
VL_WARN_MT(__FILE__, __LINE__, "randomize",
|
||||||
|
"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(nidx));
|
||||||
|
*p = VL_CLEAN_II(obits, obits, owp[0]);
|
||||||
|
} else if (obits <= VL_SHORTSIZE) {
|
||||||
|
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(nidx));
|
||||||
|
*p = VL_CLEAN_II(obits, obits, owp[0]);
|
||||||
|
} else if (obits <= VL_QUADSIZE) {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
if (varBits > 2) os << ')';
|
||||||
|
}
|
||||||
|
if (bits > 1) os << ')';
|
||||||
|
os << ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VlRandomizer::next(VlRNG& rngr) {
|
||||||
|
if (m_vars.empty()) return true;
|
||||||
|
std::iostream& f = getSolver();
|
||||||
|
if (!f) return false;
|
||||||
|
|
||||||
|
f << "(set-option :produce-models true)\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() << " () ";
|
||||||
|
var.second->emitType(f);
|
||||||
|
f << ")\n";
|
||||||
|
}
|
||||||
|
for (const std::string& constraint : m_constraints) {
|
||||||
|
f << "(assert (= #b1 " << constraint << "))\n";
|
||||||
|
}
|
||||||
|
f << "(check-sat)\n";
|
||||||
|
|
||||||
|
bool sat = parseSolution(f);
|
||||||
|
if (!sat) {
|
||||||
|
f << "(reset)\n";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < _VL_SOLVER_HASH_LEN_TOTAL && sat; i++) {
|
||||||
|
f << "(assert ";
|
||||||
|
randomConstraint(f, rngr, _VL_SOLVER_HASH_LEN);
|
||||||
|
f << ")\n";
|
||||||
|
f << "\n(check-sat)\n";
|
||||||
|
sat = parseSolution(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
f << "(reset)\n";
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VlRandomizer::parseSolution(std::iostream& f) {
|
||||||
|
std::string sat;
|
||||||
|
do { std::getline(f, sat); } while (sat == "");
|
||||||
|
|
||||||
|
if (sat == "unsat") return false;
|
||||||
|
if (sat != "sat") {
|
||||||
|
std::stringstream msg;
|
||||||
|
msg << "Internal: Solver error: " << sat;
|
||||||
|
const std::string str = msg.str();
|
||||||
|
VL_WARN_MT(__FILE__, __LINE__, "randomize", str.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
f << "(get-value (";
|
||||||
|
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))
|
||||||
|
char c;
|
||||||
|
f >> c;
|
||||||
|
if (c != '(') {
|
||||||
|
VL_WARN_MT(__FILE__, __LINE__, "randomize",
|
||||||
|
"Internal: Unable to parse solver's response: invalid S-expression");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
f >> c;
|
||||||
|
if (c == ')') break;
|
||||||
|
if (c != '(') {
|
||||||
|
VL_WARN_MT(__FILE__, __LINE__, "randomize",
|
||||||
|
"Internal: Unable to parse solver's response: invalid S-expression");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
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, ')');
|
||||||
|
const auto it = m_vars.find(name);
|
||||||
|
if (it == m_vars.end()) continue;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
VL_PRINTF("Variable (%d): %s\n", var.second->width(), var.second->name());
|
||||||
|
}
|
||||||
|
for (const std::string& c : m_constraints) VL_PRINTF("Constraint: %s\n", c.c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -0,0 +1,239 @@
|
|||||||
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
|
//*************************************************************************
|
||||||
|
//
|
||||||
|
// Code available from: https://verilator.org
|
||||||
|
//
|
||||||
|
// Copyright 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
|
||||||
|
//
|
||||||
|
//*************************************************************************
|
||||||
|
///
|
||||||
|
/// \file
|
||||||
|
/// \brief Verilated randomization header
|
||||||
|
///
|
||||||
|
/// This file is included automatically by Verilator in some of the C++ files
|
||||||
|
/// it generates if randomization features are used.
|
||||||
|
///
|
||||||
|
/// This file is not part of the Verilated public-facing API.
|
||||||
|
/// It is only for internal use.
|
||||||
|
///
|
||||||
|
/// See the internals documentation docs/internals.rst for details.
|
||||||
|
///
|
||||||
|
//*************************************************************************
|
||||||
|
#ifndef VERILATOR_VERILATED_RANDOM_H_
|
||||||
|
#define VERILATOR_VERILATED_RANDOM_H_
|
||||||
|
|
||||||
|
#include "verilated.h"
|
||||||
|
|
||||||
|
#include <ostream>
|
||||||
|
|
||||||
|
//=============================================================================
|
||||||
|
// VlRandomExpr and subclasses represent expressions for the constraint solver.
|
||||||
|
|
||||||
|
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, int dimension, std::uint32_t randModeIdx)
|
||||||
|
: m_name{name}
|
||||||
|
, m_datap{datap}
|
||||||
|
, 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; }
|
||||||
|
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; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class VlRandomQueueVar final : public VlRandomVar {
|
||||||
|
public:
|
||||||
|
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 << ')';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
class VlRandomArrayVar final : public VlRandomVar {
|
||||||
|
public:
|
||||||
|
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 << ')';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
//=============================================================================
|
||||||
|
// 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
|
||||||
|
const VlQueue<CData>* m_randmode; // rand_mode state;
|
||||||
|
|
||||||
|
// PRIVATE METHODS
|
||||||
|
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, 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
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // Guard
|
||||||
@@ -95,8 +95,7 @@ void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
|||||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, std::strlen(VLTSAVE_HEADER_STR)))) {
|
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, std::strlen(VLTSAVE_HEADER_STR)))) {
|
||||||
const std::string fn = filename();
|
const std::string fn = filename();
|
||||||
const std::string msg
|
const std::string msg
|
||||||
= std::
|
= "Can't deserialize; file has wrong header signature, or file not found: "s
|
||||||
string{"Can't deserialize; file has wrong header signature, or file not found: "}
|
|
||||||
+ filename();
|
+ filename();
|
||||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||||
// Die before we close() as close would infinite loop
|
// Die before we close() as close would infinite loop
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ package std;
|
|||||||
|
|
||||||
task put(T message);
|
task put(T message);
|
||||||
`ifdef VERILATOR_TIMING
|
`ifdef VERILATOR_TIMING
|
||||||
if (m_bound != 0)
|
while (m_bound != 0 && m_queue.size() >= m_bound)
|
||||||
wait (m_queue.size() < m_bound);
|
wait (m_queue.size() < m_bound);
|
||||||
m_queue.push_back(message);
|
m_queue.push_back(message);
|
||||||
`endif
|
`endif
|
||||||
@@ -56,7 +56,9 @@ package std;
|
|||||||
|
|
||||||
task get(ref T message);
|
task get(ref T message);
|
||||||
`ifdef VERILATOR_TIMING
|
`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();
|
message = m_queue.pop_front();
|
||||||
`endif
|
`endif
|
||||||
endtask
|
endtask
|
||||||
@@ -71,7 +73,9 @@ package std;
|
|||||||
|
|
||||||
task peek(ref T message);
|
task peek(ref T message);
|
||||||
`ifdef VERILATOR_TIMING
|
`ifdef VERILATOR_TIMING
|
||||||
wait (m_queue.size() > 0);
|
while (m_queue.size() == 0) begin
|
||||||
|
wait (m_queue.size() > 0);
|
||||||
|
end
|
||||||
message = m_queue[0];
|
message = m_queue[0];
|
||||||
`endif
|
`endif
|
||||||
endtask
|
endtask
|
||||||
@@ -98,7 +102,9 @@ package std;
|
|||||||
|
|
||||||
task get(int keyCount = 1);
|
task get(int keyCount = 1);
|
||||||
`ifdef VERILATOR_TIMING
|
`ifdef VERILATOR_TIMING
|
||||||
wait (m_keyCount >= keyCount);
|
while (m_keyCount < keyCount) begin
|
||||||
|
wait (m_keyCount >= keyCount);
|
||||||
|
end
|
||||||
m_keyCount -= keyCount;
|
m_keyCount -= keyCount;
|
||||||
`endif
|
`endif
|
||||||
endtask
|
endtask
|
||||||
@@ -189,4 +195,7 @@ package std;
|
|||||||
$urandom(s.atoi()); // Set the seed using a string
|
$urandom(s.atoi()); // Set the seed using a string
|
||||||
endfunction
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
function int randomize();
|
||||||
|
randomize = 0;
|
||||||
|
endfunction
|
||||||
endpackage
|
endpackage
|
||||||
|
|||||||
@@ -67,9 +67,16 @@ void VlDelayScheduler::resume() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!m_zeroDelayed.empty()) {
|
if (!m_zeroDelayed.empty()) {
|
||||||
for (auto&& handle : m_zeroDelayed) handle.resume();
|
// First, we need to move the coroutines out of the queue, as a resumed coroutine can
|
||||||
m_zeroDelayed.clear();
|
// suspend on #0 again, adding itself to the queue, which can result in reallocating the
|
||||||
|
// queue mid-iteration.
|
||||||
|
// We swap with the m_zeroDlyResumed field to keep the allocated buffer.
|
||||||
|
m_zeroDlyResumed.swap(m_zeroDelayed);
|
||||||
|
for (auto&& handle : m_zeroDlyResumed) handle.resume();
|
||||||
|
m_zeroDlyResumed.clear();
|
||||||
resumed = true;
|
resumed = true;
|
||||||
|
// We are now in the Active region, so any coroutines added to m_zeroDelayed in the
|
||||||
|
// meantime will have to wait until the next Inactive region.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!resumed) {
|
if (!resumed) {
|
||||||
|
|||||||
+18
-11
@@ -32,14 +32,18 @@
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
// Some preprocessor magic to support both Clang and GCC coroutines with both libc++ and libstdc++
|
// Some preprocessor magic to support both Clang and GCC coroutines with both libc++ and libstdc++
|
||||||
#if defined _LIBCPP_VERSION // libc++
|
#if defined _LIBCPP_VERSION // libc++
|
||||||
# if __clang_major__ > 13 // Clang > 13 warns that coroutine types in std::experimental are deprecated
|
# if defined(__has_include) && !__has_include(<coroutine>) && __has_include(<experimental/coroutine>)
|
||||||
# pragma clang diagnostic push
|
# if __clang_major__ > 13 // Clang > 13 warns that coroutine types in std::experimental are deprecated
|
||||||
# pragma clang diagnostic ignored "-Wdeprecated-experimental-coroutine"
|
# pragma clang diagnostic push
|
||||||
|
# pragma clang diagnostic ignored "-Wdeprecated-experimental-coroutine"
|
||||||
|
# endif
|
||||||
|
# include <experimental/coroutine>
|
||||||
|
namespace std {
|
||||||
|
using namespace experimental; // Bring std::experimental into the std namespace
|
||||||
|
}
|
||||||
|
# else
|
||||||
|
# include <coroutine>
|
||||||
# endif
|
# endif
|
||||||
# include <experimental/coroutine>
|
|
||||||
namespace std {
|
|
||||||
using namespace experimental; // Bring std::experimental into the std namespace
|
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
# if defined __clang__ && defined __GLIBCXX__ && !defined __cpp_impl_coroutine
|
# if defined __clang__ && defined __GLIBCXX__ && !defined __cpp_impl_coroutine
|
||||||
# define __cpp_impl_coroutine 1 // Clang doesn't define this, but it's needed for libstdc++
|
# define __cpp_impl_coroutine 1 // Clang doesn't define this, but it's needed for libstdc++
|
||||||
@@ -165,6 +169,9 @@ class VlDelayScheduler final {
|
|||||||
VerilatedContext& m_context;
|
VerilatedContext& m_context;
|
||||||
VlDelayedCoroutineQueue m_queue; // Coroutines to be restored at a certain simulation time
|
VlDelayedCoroutineQueue m_queue; // Coroutines to be restored at a certain simulation time
|
||||||
std::vector<VlCoroutineHandle> m_zeroDelayed; // Coroutines waiting for #0
|
std::vector<VlCoroutineHandle> m_zeroDelayed; // Coroutines waiting for #0
|
||||||
|
std::vector<VlCoroutineHandle> m_zeroDlyResumed; // Coroutines that waited for #0 and are
|
||||||
|
// to be resumed. Kept as a field to avoid
|
||||||
|
// reallocation.
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
@@ -193,9 +200,9 @@ public:
|
|||||||
VlProcessRef process; // Data of the suspended process, null if not needed
|
VlProcessRef process; // Data of the suspended process, null if not needed
|
||||||
VlDelayedCoroutineQueue& queue;
|
VlDelayedCoroutineQueue& queue;
|
||||||
std::vector<VlCoroutineHandle>& queueZeroDelay;
|
std::vector<VlCoroutineHandle>& queueZeroDelay;
|
||||||
uint64_t delay;
|
const uint64_t delay;
|
||||||
VlDelayPhase phase;
|
const VlDelayPhase phase;
|
||||||
VlFileLineDebug fileline;
|
const VlFileLineDebug fileline;
|
||||||
|
|
||||||
bool await_ready() const { return false; } // Always suspend
|
bool await_ready() const { return false; } // Always suspend
|
||||||
void await_suspend(std::coroutine_handle<> coro) {
|
void await_suspend(std::coroutine_handle<> coro) {
|
||||||
@@ -208,7 +215,7 @@ public:
|
|||||||
void await_resume() const {}
|
void await_resume() const {}
|
||||||
};
|
};
|
||||||
|
|
||||||
VlDelayPhase phase = (delay == 0) ? VlDelayPhase::INACTIVE : VlDelayPhase::ACTIVE;
|
const VlDelayPhase phase = (delay == 0) ? VlDelayPhase::INACTIVE : VlDelayPhase::ACTIVE;
|
||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
if (phase == VlDelayPhase::INACTIVE) {
|
if (phase == VlDelayPhase::INACTIVE) {
|
||||||
VL_WARN_MT(filename, lineno, VL_UNKNOWN,
|
VL_WARN_MT(filename, lineno, VL_UNKNOWN,
|
||||||
|
|||||||
+26
-18
@@ -30,8 +30,9 @@
|
|||||||
#include <condition_variable>
|
#include <condition_variable>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <type_traits>
|
||||||
#include <unordered_set>
|
#include <map>
|
||||||
|
#include <set>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <deque>
|
#include <deque>
|
||||||
@@ -48,10 +49,12 @@ class VerilatedTraceOffloadBuffer;
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Common enumerations
|
// Common enumerations
|
||||||
|
|
||||||
enum class VerilatedTracePrefixType : uint32_t {
|
enum class VerilatedTracePrefixType : uint8_t {
|
||||||
// Note: Entries must match VTracePrefixType (by name, not necessarily by value)
|
// Note: Entries must match VTracePrefixType (by name, not necessarily by value)
|
||||||
ARRAY_PACKED,
|
ARRAY_PACKED,
|
||||||
ARRAY_UNPACKED,
|
ARRAY_UNPACKED,
|
||||||
|
ROOTIO_MODULE, // $rootio, used when name()=="", other modules become peers
|
||||||
|
ROOTIO_WRAPPER, // "Above" ROOTIO_MODULE
|
||||||
SCOPE_MODULE,
|
SCOPE_MODULE,
|
||||||
SCOPE_INTERFACE,
|
SCOPE_INTERFACE,
|
||||||
STRUCT_PACKED,
|
STRUCT_PACKED,
|
||||||
@@ -60,7 +63,7 @@ enum class VerilatedTracePrefixType : uint32_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Direction attribute for ports
|
// Direction attribute for ports
|
||||||
enum class VerilatedTraceSigDirection : uint32_t {
|
enum class VerilatedTraceSigDirection : uint8_t {
|
||||||
NONE,
|
NONE,
|
||||||
INPUT,
|
INPUT,
|
||||||
OUTPUT,
|
OUTPUT,
|
||||||
@@ -68,7 +71,7 @@ enum class VerilatedTraceSigDirection : uint32_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Kind of signal. Similar to nettype but with a few more alternatives
|
// Kind of signal. Similar to nettype but with a few more alternatives
|
||||||
enum class VerilatedTraceSigKind : uint32_t {
|
enum class VerilatedTraceSigKind : uint8_t {
|
||||||
PARAMETER,
|
PARAMETER,
|
||||||
SUPPLY0,
|
SUPPLY0,
|
||||||
SUPPLY1,
|
SUPPLY1,
|
||||||
@@ -80,7 +83,7 @@ enum class VerilatedTraceSigKind : uint32_t {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Base data type of signal
|
// Base data type of signal
|
||||||
enum class VerilatedTraceSigType : uint32_t {
|
enum class VerilatedTraceSigType : uint8_t {
|
||||||
DOUBLE,
|
DOUBLE,
|
||||||
INTEGER,
|
INTEGER,
|
||||||
BIT,
|
BIT,
|
||||||
@@ -197,8 +200,8 @@ public:
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedTrace
|
// VerilatedTrace
|
||||||
|
|
||||||
// T_Trace is the format specific subclass of VerilatedTrace.
|
// T_Trace is the format-specific subclass of VerilatedTrace.
|
||||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
// T_Buffer is the format-specific base class of VerilatedTraceBuffer.
|
||||||
template <class T_Trace, class T_Buffer>
|
template <class T_Trace, class T_Buffer>
|
||||||
class VerilatedTrace VL_NOT_FINAL {
|
class VerilatedTrace VL_NOT_FINAL {
|
||||||
public:
|
public:
|
||||||
@@ -294,7 +297,7 @@ private:
|
|||||||
uint64_t m_timeLastDump = 0; // Last time we did a dump
|
uint64_t m_timeLastDump = 0; // Last time we did a dump
|
||||||
bool m_didSomeDump = false; // Did at least one dump (i.e.: m_timeLastDump is valid)
|
bool m_didSomeDump = false; // Did at least one dump (i.e.: m_timeLastDump is valid)
|
||||||
VerilatedContext* m_contextp = nullptr; // The context used by the traced models
|
VerilatedContext* m_contextp = nullptr; // The context used by the traced models
|
||||||
std::unordered_set<const VerilatedModel*> m_models; // The collection of models being traced
|
std::set<const VerilatedModel*> m_models; // The collection of models being traced
|
||||||
|
|
||||||
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord&& cbRec)
|
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord&& cbRec)
|
||||||
VL_MT_SAFE_EXCLUDES(m_mutex);
|
VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||||
@@ -347,7 +350,7 @@ private:
|
|||||||
|
|
||||||
protected:
|
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
|
mutable VerilatedMutex m_mutex; // Ensure dump() etc only called from single thread
|
||||||
|
|
||||||
@@ -380,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
|
// Called when the trace moves forward to a new time point
|
||||||
virtual void emitTimeChange(uint64_t timeui) = 0;
|
virtual void emitTimeChange(uint64_t timeui) = 0;
|
||||||
@@ -437,7 +440,7 @@ public:
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedTraceBuffer
|
// 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.
|
// The format-specific hot-path methods use duck-typing via T_Buffer for performance.
|
||||||
template <class T_Buffer>
|
template <class T_Buffer>
|
||||||
class VerilatedTraceBuffer VL_NOT_FINAL : public T_Buffer {
|
class VerilatedTraceBuffer VL_NOT_FINAL : public T_Buffer {
|
||||||
@@ -463,7 +466,7 @@ public:
|
|||||||
// Hot path internal interface to Verilator generated code
|
// Hot path internal interface to Verilator generated code
|
||||||
|
|
||||||
// Implementation note: We rely on the following duck-typed implementations
|
// 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
|
// specific trace entry. Normally one would use pure virtual functions for
|
||||||
// these here, but we cannot afford dynamic dispatch for calling these as
|
// these here, but we cannot afford dynamic dispatch for calling these as
|
||||||
// this is very hot code during tracing.
|
// this is very hot code during tracing.
|
||||||
@@ -486,7 +489,8 @@ public:
|
|||||||
void fullQData(uint32_t* oldp, QData newval, int bits);
|
void fullQData(uint32_t* oldp, QData newval, int bits);
|
||||||
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
|
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
|
||||||
void fullDouble(uint32_t* oldp, double newval);
|
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,
|
// 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
|
// and are called chg*. In offload mode, they are called by the worker
|
||||||
@@ -523,9 +527,10 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newval) {
|
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, const VlEventBase* newvalp) {
|
||||||
fullEvent(oldp, newval);
|
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) {
|
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
|
||||||
double old;
|
double old;
|
||||||
std::memcpy(&old, oldp, sizeof(old));
|
std::memcpy(&old, oldp, sizeof(old));
|
||||||
@@ -536,7 +541,7 @@ public:
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VerilatedTraceOffloadBuffer
|
// 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.
|
// The format-specific hot-path methods use duck-typing via T_Buffer for performance.
|
||||||
template <class T_Buffer>
|
template <class T_Buffer>
|
||||||
class VerilatedTraceOffloadBuffer final : public VerilatedTraceBuffer<T_Buffer> {
|
class VerilatedTraceOffloadBuffer final : public VerilatedTraceBuffer<T_Buffer> {
|
||||||
@@ -604,7 +609,10 @@ public:
|
|||||||
m_offloadBufferWritep += 4;
|
m_offloadBufferWritep += 4;
|
||||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
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[0] = VerilatedTraceOffloadCommand::CHG_EVENT;
|
||||||
m_offloadBufferWritep[1] = code;
|
m_offloadBufferWritep[1] = code;
|
||||||
m_offloadBufferWritep += 2;
|
m_offloadBufferWritep += 2;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@
|
|||||||
//=============================================================================
|
//=============================================================================
|
||||||
//
|
//
|
||||||
// Verilated tracing implementation code template common to all formats.
|
// 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.
|
// should not be used otherwise.
|
||||||
//
|
//
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
@@ -169,7 +169,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
|||||||
continue;
|
continue;
|
||||||
case VerilatedTraceOffloadCommand::CHG_EVENT:
|
case VerilatedTraceOffloadCommand::CHG_EVENT:
|
||||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
|
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
|
||||||
traceBufp->chgEvent(oldp, reinterpret_cast<const VlEventBase*>(readp));
|
traceBufp->chgEventTriggered(oldp);
|
||||||
continue;
|
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 <>
|
template <>
|
||||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
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 <>
|
template <>
|
||||||
std::string VerilatedTrace<VL_SUB_T, VL_BUF_T>::timeResStr() const {
|
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();
|
Verilated::quiesce();
|
||||||
|
|
||||||
// Call hook for format specific behaviour
|
// Call hook for format-specific behaviour
|
||||||
if (VL_UNLIKELY(m_fullDump)) {
|
if (VL_UNLIKELY(m_fullDump)) {
|
||||||
if (!preFullDump()) return;
|
if (!preFullDump()) return;
|
||||||
} else {
|
} else {
|
||||||
@@ -633,12 +633,13 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addModel(VerilatedModel* modelp)
|
|||||||
|
|
||||||
// Validate
|
// Validate
|
||||||
if (!newModel) { // LCOV_EXCL_START
|
if (!newModel) { // LCOV_EXCL_START
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
VL_FATAL_MT(
|
||||||
"The same model has already been added to this trace file");
|
__FILE__, __LINE__, "",
|
||||||
|
"The same model has already been added to this trace file or VerilatedContext");
|
||||||
}
|
}
|
||||||
if (VL_UNCOVERABLE(m_contextp && contextp != m_contextp)) {
|
if (VL_UNCOVERABLE(m_contextp && contextp != m_contextp)) {
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||||
"A trace file instance can only handle models from the same context");
|
"A trace file instance can only handle models from the same VerilatedContext");
|
||||||
}
|
}
|
||||||
if (VL_UNCOVERABLE(m_didSomeDump)) {
|
if (VL_UNCOVERABLE(m_didSomeDump)) {
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||||
@@ -666,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");
|
VL_FATAL_MT(__FILE__, __LINE__, "", "Cannot use parallel tracing with offloading");
|
||||||
} // LCOV_EXCL_STOP
|
} // LCOV_EXCL_STOP
|
||||||
|
|
||||||
// Configure format specific sub class
|
// Configure format-specific sub class
|
||||||
configure(*(configp.get()));
|
configure(*(configp.get()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -817,8 +818,8 @@ VerilatedTraceBuffer<VL_BUF_T>::VerilatedTraceBuffer(Trace& owner)
|
|||||||
, m_sigs_enabledp{owner.m_sigs_enabledp} {}
|
, m_sigs_enabledp{owner.m_sigs_enabledp} {}
|
||||||
|
|
||||||
// These functions must write the new value back into the old value store,
|
// These functions must write the new value back into the old value store,
|
||||||
// and subsequently call the format specific emit* implementations. Note
|
// and subsequently call the format-specific emit* implementations. Note
|
||||||
// that this file must be included in the format specific implementation, so
|
// that this file must be included in the format-specific implementation, so
|
||||||
// the emit* functions can be inlined for performance.
|
// the emit* functions can be inlined for performance.
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
@@ -830,10 +831,17 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <>
|
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;
|
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||||
*oldp = 1; // Do we really store an "event" ?
|
// No need to update *oldp
|
||||||
emitEvent(code, newval);
|
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 <>
|
template <>
|
||||||
|
|||||||
+345
-104
@@ -36,7 +36,6 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
@@ -415,8 +414,20 @@ public:
|
|||||||
|
|
||||||
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
|
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
|
||||||
|
|
||||||
|
template <std::size_t T_Words>
|
||||||
|
struct VlWide;
|
||||||
|
|
||||||
|
// Type trait to check if a type is VlWide
|
||||||
|
template <typename>
|
||||||
|
struct VlIsVlWide : public std::false_type {};
|
||||||
|
|
||||||
|
template <std::size_t T_Words>
|
||||||
|
struct VlIsVlWide<VlWide<T_Words>> : public std::true_type {};
|
||||||
|
|
||||||
template <std::size_t T_Words>
|
template <std::size_t T_Words>
|
||||||
struct VlWide final {
|
struct VlWide final {
|
||||||
|
static constexpr size_t Words = T_Words;
|
||||||
|
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
// This should be the only data member, otherwise generated static initializers need updating
|
// This should be the only data member, otherwise generated static initializers need updating
|
||||||
EData m_storage[T_Words]; // Contents of the packed array
|
EData m_storage[T_Words]; // Contents of the packed array
|
||||||
@@ -474,6 +485,8 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
using const_iterator = typename Deque::const_iterator;
|
using const_iterator = typename Deque::const_iterator;
|
||||||
|
template <class Func>
|
||||||
|
using WithFuncReturnType = decltype(std::declval<Func>()(0, std::declval<T_Value>()));
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
@@ -501,28 +514,29 @@ public:
|
|||||||
return *this;
|
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;
|
VlQueue out;
|
||||||
out.push_back(lhs);
|
out.push_back(lhs);
|
||||||
return out;
|
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;
|
VlQueue out;
|
||||||
out.push_back(rhs);
|
out.push_back(rhs);
|
||||||
out.push_back(lhs);
|
out.push_back(lhs);
|
||||||
return out;
|
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;
|
VlQueue out = lhs;
|
||||||
out.push_front(rhs);
|
out.push_front(rhs);
|
||||||
return out;
|
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;
|
VlQueue out = rhs;
|
||||||
out.push_back(lhs);
|
out.push_back(lhs);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
static VlQueue cons(const VlQueue& lhs, const VlQueue& rhs) {
|
static VlQueue consCC(const VlQueue& lhs, const VlQueue& rhs) {
|
||||||
VlQueue out = rhs;
|
VlQueue out = rhs;
|
||||||
for (const auto& i : lhs.m_deque) out.push_back(i);
|
for (const auto& i : lhs.m_deque) out.push_back(i);
|
||||||
return out;
|
return out;
|
||||||
@@ -581,18 +595,28 @@ public:
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Setting. Verilog: assoc[index] = v
|
// Setting. Verilog: assoc[index] = v (should only be used by dynamic arrays)
|
||||||
// Can't just overload operator[] or provide a "at" reference to set,
|
T_Value& atWrite(int32_t index) {
|
||||||
// because we need to be able to insert only when the value is set
|
// cppcheck-suppress variableScope
|
||||||
T_Value& at(int32_t index) {
|
|
||||||
static thread_local T_Value t_throwAway;
|
static thread_local T_Value t_throwAway;
|
||||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||||
t_throwAway = atDefault();
|
t_throwAway = atDefault();
|
||||||
return t_throwAway;
|
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]
|
// Accessing. Verilog: v = assoc[index]
|
||||||
const T_Value& at(int32_t index) const {
|
const T_Value& at(int32_t index) const {
|
||||||
@@ -604,7 +628,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Access with an index counted from end (e.g. q[$])
|
// 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); }
|
const T_Value& atBack(int32_t index) const { return at(m_deque.size() - 1 - index); }
|
||||||
|
|
||||||
// function void q.insert(index, value);
|
// function void q.insert(index, value);
|
||||||
@@ -740,7 +764,7 @@ public:
|
|||||||
// Can't use std::find_if as need index number
|
// Can't use std::find_if as need index number
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
for (const auto& i : m_deque) {
|
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;
|
++index;
|
||||||
}
|
}
|
||||||
return VlQueue{};
|
return VlQueue{};
|
||||||
@@ -749,7 +773,7 @@ public:
|
|||||||
VlQueue<IData> find_first_index(Func with_func) const {
|
VlQueue<IData> find_first_index(Func with_func) const {
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
for (const auto& i : m_deque) {
|
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;
|
++index;
|
||||||
}
|
}
|
||||||
return VlQueue<IData>{};
|
return VlQueue<IData>{};
|
||||||
@@ -758,7 +782,7 @@ public:
|
|||||||
VlQueue find_last(Func with_func) const {
|
VlQueue find_last(Func with_func) const {
|
||||||
IData index = m_deque.size() - 1;
|
IData index = m_deque.size() - 1;
|
||||||
for (auto& item : vlstd::reverse_view(m_deque)) {
|
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;
|
--index;
|
||||||
}
|
}
|
||||||
return VlQueue{};
|
return VlQueue{};
|
||||||
@@ -767,7 +791,7 @@ public:
|
|||||||
VlQueue<IData> find_last_index(Func with_func) const {
|
VlQueue<IData> find_last_index(Func with_func) const {
|
||||||
IData index = m_deque.size() - 1;
|
IData index = m_deque.size() - 1;
|
||||||
for (auto& item : vlstd::reverse_view(m_deque)) {
|
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;
|
--index;
|
||||||
}
|
}
|
||||||
return VlQueue<IData>{};
|
return VlQueue<IData>{};
|
||||||
@@ -777,7 +801,7 @@ public:
|
|||||||
VlQueue min() const {
|
VlQueue min() const {
|
||||||
if (m_deque.empty()) return VlQueue{};
|
if (m_deque.empty()) return VlQueue{};
|
||||||
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend());
|
const auto it = std::min_element(m_deque.cbegin(), m_deque.cend());
|
||||||
return VlQueue::cons(*it);
|
return VlQueue::consV(*it);
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
VlQueue min(Func with_func) const {
|
VlQueue min(Func with_func) const {
|
||||||
@@ -786,12 +810,12 @@ public:
|
|||||||
[&with_func](const IData& a, const IData& b) {
|
[&with_func](const IData& a, const IData& b) {
|
||||||
return with_func(0, a) < with_func(0, b);
|
return with_func(0, a) < with_func(0, b);
|
||||||
});
|
});
|
||||||
return VlQueue::cons(*it);
|
return VlQueue::consV(*it);
|
||||||
}
|
}
|
||||||
VlQueue max() const {
|
VlQueue max() const {
|
||||||
if (m_deque.empty()) return VlQueue{};
|
if (m_deque.empty()) return VlQueue{};
|
||||||
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend());
|
const auto it = std::max_element(m_deque.cbegin(), m_deque.cend());
|
||||||
return VlQueue::cons(*it);
|
return VlQueue::consV(*it);
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
VlQueue max(Func with_func) const {
|
VlQueue max(Func with_func) const {
|
||||||
@@ -800,7 +824,7 @@ public:
|
|||||||
[&with_func](const IData& a, const IData& b) {
|
[&with_func](const IData& a, const IData& b) {
|
||||||
return with_func(0, a) < with_func(0, b);
|
return with_func(0, a) < with_func(0, b);
|
||||||
});
|
});
|
||||||
return VlQueue::cons(*it);
|
return VlQueue::consV(*it);
|
||||||
}
|
}
|
||||||
|
|
||||||
T_Value r_sum() const {
|
T_Value r_sum() const {
|
||||||
@@ -809,70 +833,63 @@ public:
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_sum(Func with_func) const {
|
WithFuncReturnType<Func> r_sum(Func with_func) const {
|
||||||
T_Value out(0); // Type must have assignment operator
|
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
for (const auto& i : m_deque) out += with_func(index++, i);
|
for (const auto& i : m_deque) out += with_func(index++, i);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
T_Value r_product() const {
|
T_Value r_product() const {
|
||||||
if (m_deque.empty()) return T_Value(0);
|
if (m_deque.empty()) return T_Value(0); // The big three do it this way
|
||||||
auto it = m_deque.cbegin();
|
T_Value out = T_Value(1);
|
||||||
T_Value out{*it};
|
for (const auto& i : m_deque) out *= i;
|
||||||
++it;
|
|
||||||
for (; it != m_deque.cend(); ++it) out *= *it;
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_product(Func with_func) const {
|
WithFuncReturnType<Func> r_product(Func with_func) const {
|
||||||
if (m_deque.empty()) return T_Value(0);
|
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||||
auto it = m_deque.cbegin();
|
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
T_Value out{with_func(index, *it)};
|
for (const auto& i : m_deque) out *= with_func(index++, i);
|
||||||
++it;
|
|
||||||
++index;
|
|
||||||
for (; it != m_deque.cend(); ++it) out *= with_func(index++, *it);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
T_Value r_and() const {
|
T_Value r_and() const {
|
||||||
if (m_deque.empty()) return T_Value(0);
|
if (m_deque.empty()) return T_Value(0); // The big three do it this way
|
||||||
auto it = m_deque.cbegin();
|
T_Value out = ~T_Value(0);
|
||||||
T_Value out{*it};
|
for (const auto& i : m_deque) out &= i;
|
||||||
++it;
|
|
||||||
for (; it != m_deque.cend(); ++it) out &= *it;
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_and(Func with_func) const {
|
WithFuncReturnType<Func> r_and(Func with_func) const {
|
||||||
if (m_deque.empty()) return T_Value(0);
|
if (m_deque.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||||
auto it = m_deque.cbegin();
|
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
T_Value out{with_func(index, *it)};
|
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
|
||||||
++it;
|
for (const auto& i : m_deque) out &= with_func(index++, i);
|
||||||
++index;
|
|
||||||
for (; it != m_deque.cend(); ++it) out &= with_func(index, *it);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
T_Value r_or() const {
|
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;
|
for (const auto& i : m_deque) out |= i;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_or(Func with_func) const {
|
WithFuncReturnType<Func> r_or(Func with_func) const {
|
||||||
T_Value out(0); // Type must have assignment operator
|
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
for (const auto& i : m_deque) out |= with_func(index++, i);
|
for (const auto& i : m_deque) out |= with_func(index++, i);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
T_Value r_xor() const {
|
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;
|
for (const auto& i : m_deque) out ^= i;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_xor(Func with_func) const {
|
WithFuncReturnType<Func> r_xor(Func with_func) const {
|
||||||
T_Value out(0); // Type must have assignment operator
|
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
for (const auto& i : m_deque) out ^= with_func(index++, i);
|
for (const auto& i : m_deque) out ^= with_func(index++, i);
|
||||||
return out;
|
return out;
|
||||||
@@ -891,8 +908,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T_Value>
|
template <class T_Value, size_t T_MaxSize>
|
||||||
std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
std::string VL_TO_STRING(const VlQueue<T_Value, T_MaxSize>& obj) {
|
||||||
return obj.to_string();
|
return obj.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -909,6 +926,9 @@ private:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
using const_iterator = typename Map::const_iterator;
|
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:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
@@ -1081,7 +1101,7 @@ public:
|
|||||||
return with_func(i.first, i.second);
|
return with_func(i.first, i.second);
|
||||||
});
|
});
|
||||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
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>
|
template <typename Func>
|
||||||
VlQueue<T_Key> find_first_index(Func with_func) const {
|
VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||||
@@ -1090,7 +1110,7 @@ public:
|
|||||||
return with_func(i.first, i.second);
|
return with_func(i.first, i.second);
|
||||||
});
|
});
|
||||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
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>
|
template <typename Func>
|
||||||
VlQueue<T_Value> find_last(Func with_func) const {
|
VlQueue<T_Value> find_last(Func with_func) const {
|
||||||
@@ -1098,7 +1118,7 @@ public:
|
|||||||
m_map.crbegin(), m_map.crend(),
|
m_map.crbegin(), m_map.crend(),
|
||||||
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
|
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
|
||||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
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>
|
template <typename Func>
|
||||||
VlQueue<T_Key> find_last_index(Func with_func) const {
|
VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||||
@@ -1106,7 +1126,7 @@ public:
|
|||||||
m_map.crbegin(), m_map.crend(),
|
m_map.crbegin(), m_map.crend(),
|
||||||
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
|
[=](const std::pair<T_Key, T_Value>& i) { return with_func(i.first, i.second); });
|
||||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
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
|
// Reduction operators
|
||||||
@@ -1117,7 +1137,7 @@ public:
|
|||||||
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||||
return a.second < b.second;
|
return a.second < b.second;
|
||||||
});
|
});
|
||||||
return VlQueue<T_Value>::cons(it->second);
|
return VlQueue<T_Value>::consV(it->second);
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
VlQueue<T_Value> min(Func with_func) const {
|
VlQueue<T_Value> min(Func with_func) const {
|
||||||
@@ -1127,7 +1147,7 @@ public:
|
|||||||
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
[&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 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 {
|
VlQueue<T_Value> max() const {
|
||||||
if (m_map.empty()) return VlQueue<T_Value>();
|
if (m_map.empty()) return VlQueue<T_Value>();
|
||||||
@@ -1136,7 +1156,7 @@ public:
|
|||||||
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
[](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
||||||
return a.second < b.second;
|
return a.second < b.second;
|
||||||
});
|
});
|
||||||
return VlQueue<T_Value>::cons(it->second);
|
return VlQueue<T_Value>::consV(it->second);
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
VlQueue<T_Value> max(Func with_func) const {
|
VlQueue<T_Value> max(Func with_func) const {
|
||||||
@@ -1146,7 +1166,7 @@ public:
|
|||||||
[&with_func](const std::pair<T_Key, T_Value>& a, const std::pair<T_Key, T_Value>& b) {
|
[&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 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 {
|
T_Value r_sum() const {
|
||||||
@@ -1155,64 +1175,56 @@ public:
|
|||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_sum(Func with_func) const {
|
WithFuncReturnType<Func> r_sum(Func with_func) const {
|
||||||
T_Value out(0); // Type must have assignment operator
|
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||||
for (const auto& i : m_map) out += with_func(i.first, i.second);
|
for (const auto& i : m_map) out += with_func(i.first, i.second);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
T_Value r_product() const {
|
T_Value r_product() const {
|
||||||
if (m_map.empty()) return T_Value(0);
|
if (m_map.empty()) return T_Value(0); // The big three do it this way
|
||||||
auto it = m_map.cbegin();
|
T_Value out = T_Value(1);
|
||||||
T_Value out{it->second};
|
for (const auto& i : m_map) out *= i.second;
|
||||||
++it;
|
|
||||||
for (; it != m_map.cend(); ++it) out *= it->second;
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_product(Func with_func) const {
|
WithFuncReturnType<Func> r_product(Func with_func) const {
|
||||||
if (m_map.empty()) return T_Value(0);
|
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||||
auto it = m_map.cbegin();
|
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(1);
|
||||||
T_Value out{with_func(it->first, it->second)};
|
for (const auto& i : m_map) out *= with_func(i.first, i.second);
|
||||||
++it;
|
|
||||||
for (; it != m_map.cend(); ++it) out *= with_func(it->first, it->second);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
T_Value r_and() const {
|
T_Value r_and() const {
|
||||||
if (m_map.empty()) return T_Value(0);
|
if (m_map.empty()) return T_Value(0); // The big three do it this way
|
||||||
auto it = m_map.cbegin();
|
T_Value out = ~T_Value(0);
|
||||||
T_Value out{it->second};
|
for (const auto& i : m_map) out &= i.second;
|
||||||
++it;
|
|
||||||
for (; it != m_map.cend(); ++it) out &= it->second;
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_and(Func with_func) const {
|
WithFuncReturnType<Func> r_and(Func with_func) const {
|
||||||
if (m_map.empty()) return T_Value(0);
|
if (m_map.empty()) return WithFuncReturnType<Func>(0); // The big three do it this way
|
||||||
auto it = m_map.cbegin();
|
WithFuncReturnType<Func> out = ~WithFuncReturnType<Func>(0);
|
||||||
T_Value out{with_func(it->first, it->second)};
|
for (const auto& i : m_map) out &= with_func(i.first, i.second);
|
||||||
++it;
|
|
||||||
for (; it != m_map.cend(); ++it) out &= with_func(it->first, it->second);
|
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
T_Value r_or() const {
|
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;
|
for (const auto& i : m_map) out |= i.second;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_or(Func with_func) const {
|
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);
|
for (const auto& i : m_map) out |= with_func(i.first, i.second);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
T_Value r_xor() const {
|
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;
|
for (const auto& i : m_map) out ^= i.second;
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
T_Value r_xor(Func with_func) const {
|
WithFuncReturnType<Func> r_xor(Func with_func) const {
|
||||||
T_Value out(0); // Type must have assignment operator
|
WithFuncReturnType<Func> out = WithFuncReturnType<Func>(0);
|
||||||
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
|
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -1300,6 +1312,43 @@ public:
|
|||||||
WData* data() { return &m_storage[0]; }
|
WData* data() { return &m_storage[0]; }
|
||||||
const WData* data() const { 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]; }
|
T_Value& operator[](size_t index) { return m_storage[index]; }
|
||||||
const T_Value& operator[](size_t index) const { return m_storage[index]; }
|
const T_Value& operator[](size_t index) const { return m_storage[index]; }
|
||||||
|
|
||||||
@@ -1309,7 +1358,11 @@ public:
|
|||||||
// Similar to 'neq' above, *this = that used for change detection
|
// Similar to 'neq' above, *this = that used for change detection
|
||||||
void assign(const VlUnpacked<T_Value, T_Depth>& that) { *this = that; }
|
void assign(const VlUnpacked<T_Value, T_Depth>& that) { *this = that; }
|
||||||
bool operator==(const VlUnpacked<T_Value, T_Depth>& that) const { return !neq(that); }
|
bool operator==(const VlUnpacked<T_Value, T_Depth>& that) const { return !neq(that); }
|
||||||
bool operator!=(const VlUnpacked<T_Value, T_Depth>& that) { return neq(that); }
|
bool operator!=(const VlUnpacked<T_Value, T_Depth>& that) const { return neq(that); }
|
||||||
|
// interface to C style arrays (used in ports), see issue #5125
|
||||||
|
bool neq(const T_Value that[T_Depth]) const { return neq(*this, that); }
|
||||||
|
void assign(const T_Value that[T_Depth]) { std::copy_n(that, T_Depth, m_storage); }
|
||||||
|
void operator=(const T_Value that[T_Depth]) { assign(that); }
|
||||||
|
|
||||||
// inside (set membership operator)
|
// inside (set membership operator)
|
||||||
bool inside(const T_Value& value) const {
|
bool inside(const T_Value& value) const {
|
||||||
@@ -1386,7 +1439,7 @@ public:
|
|||||||
VlQueue<T_Key> unique_index(Func with_func) const {
|
VlQueue<T_Key> unique_index(Func with_func) const {
|
||||||
VlQueue<T_Key> out;
|
VlQueue<T_Key> out;
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
std::unordered_set<T_Value> saw;
|
std::set<T_Value> saw;
|
||||||
for (const auto& i : m_storage) {
|
for (const auto& i : m_storage) {
|
||||||
const auto i_mapped = with_func(index, i);
|
const auto i_mapped = with_func(index, i);
|
||||||
auto it = saw.find(i_mapped);
|
auto it = saw.find(i_mapped);
|
||||||
@@ -1423,7 +1476,7 @@ public:
|
|||||||
// Can't use std::find_if as need index number
|
// Can't use std::find_if as need index number
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
for (const auto& i : m_storage) {
|
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;
|
++index;
|
||||||
}
|
}
|
||||||
return VlQueue<T_Value>{};
|
return VlQueue<T_Value>{};
|
||||||
@@ -1432,7 +1485,7 @@ public:
|
|||||||
VlQueue<T_Key> find_first_index(Func with_func) const {
|
VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||||
IData index = 0;
|
IData index = 0;
|
||||||
for (const auto& i : m_storage) {
|
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;
|
++index;
|
||||||
}
|
}
|
||||||
return VlQueue<T_Key>{};
|
return VlQueue<T_Key>{};
|
||||||
@@ -1440,14 +1493,14 @@ public:
|
|||||||
template <typename Func>
|
template <typename Func>
|
||||||
VlQueue<T_Value> find_last(Func with_func) const {
|
VlQueue<T_Value> find_last(Func with_func) const {
|
||||||
for (int i = T_Depth - 1; i >= 0; i--) {
|
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>{};
|
return VlQueue<T_Value>{};
|
||||||
}
|
}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
VlQueue<T_Key> find_last_index(Func with_func) const {
|
VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||||
for (int i = T_Depth - 1; i >= 0; i--) {
|
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>{};
|
return VlQueue<T_Key>{};
|
||||||
}
|
}
|
||||||
@@ -1455,7 +1508,7 @@ public:
|
|||||||
// Reduction operators
|
// Reduction operators
|
||||||
VlQueue<T_Value> min() const {
|
VlQueue<T_Value> min() const {
|
||||||
const auto it = std::min_element(std::begin(m_storage), std::end(m_storage));
|
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>
|
template <typename Func>
|
||||||
VlQueue<T_Value> min(Func with_func) const {
|
VlQueue<T_Value> min(Func with_func) const {
|
||||||
@@ -1463,11 +1516,11 @@ public:
|
|||||||
[&with_func](const IData& a, const IData& b) {
|
[&with_func](const IData& a, const IData& b) {
|
||||||
return with_func(0, a) < with_func(0, 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 {
|
VlQueue<T_Value> max() const {
|
||||||
const auto it = std::max_element(std::begin(m_storage), std::end(m_storage));
|
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>
|
template <typename Func>
|
||||||
VlQueue<T_Value> max(Func with_func) const {
|
VlQueue<T_Value> max(Func with_func) const {
|
||||||
@@ -1475,7 +1528,7 @@ public:
|
|||||||
[&with_func](const IData& a, const IData& b) {
|
[&with_func](const IData& a, const IData& b) {
|
||||||
return with_func(0, a) < with_func(0, 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)
|
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||||
@@ -1499,6 +1552,15 @@ private:
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T_Val, std::size_t T_Dep>
|
||||||
|
static bool neq(const VlUnpacked<T_Val, T_Dep>& a, const T_Val b[T_Dep]) {
|
||||||
|
for (size_t i = 0; i < T_Dep; ++i) {
|
||||||
|
// Recursive 'neq', in case T_Val is also a VlUnpacked<_, _>
|
||||||
|
if (neq(a.m_storage[i], b[i])) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T_Other> //
|
template <typename T_Other> //
|
||||||
static bool neq(const T_Other& a, const T_Other& b) {
|
static bool neq(const T_Other& a, const T_Other& b) {
|
||||||
// Base case (T_Other is not VlUnpacked<_, _>), fall back on !=
|
// Base case (T_Other is not VlUnpacked<_, _>), fall back on !=
|
||||||
@@ -1511,6 +1573,181 @@ std::string VL_TO_STRING(const VlUnpacked<T_Value, T_Depth>& obj) {
|
|||||||
return obj.to_string();
|
return obj.to_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===================================================================
|
||||||
|
// Helper to apply the given indices to a target expression
|
||||||
|
|
||||||
|
template <size_t Curr, size_t Rank, typename T_Target>
|
||||||
|
struct VlApplyIndices final {
|
||||||
|
VL_ATTR_ALWINLINE
|
||||||
|
static auto& apply(T_Target& target, const size_t* indicesp) {
|
||||||
|
return VlApplyIndices<Curr + 1, Rank, decltype(target[indicesp[Curr]])>::apply(
|
||||||
|
target[indicesp[Curr]], indicesp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <size_t Rank, typename T_Target>
|
||||||
|
struct VlApplyIndices<Rank, Rank, T_Target> final {
|
||||||
|
VL_ATTR_ALWINLINE
|
||||||
|
static T_Target& apply(T_Target& target, const size_t*) { return target; }
|
||||||
|
};
|
||||||
|
|
||||||
|
//===================================================================
|
||||||
|
// Commit queue for NBAs - currently only for unpacked arrays
|
||||||
|
//
|
||||||
|
// This data-structure is used to handle non-blocking assignments
|
||||||
|
// that might execute a variable number of times in a single
|
||||||
|
// evaluation. It has 2 operations:
|
||||||
|
// - 'enqueue' will add an update to the queue
|
||||||
|
// - 'commit' will apply all enqueued updates to the target variable,
|
||||||
|
// in the order they were enqueued. This ensures the last NBA
|
||||||
|
// takes effect as it is expected.
|
||||||
|
// There are 2 specializations of this class below:
|
||||||
|
// - A version when a partial element update is not required,
|
||||||
|
// e.g, to handle:
|
||||||
|
// logic [31:0] array[N];
|
||||||
|
// for (int i = 0 ; i < N ; ++i) array[i] <= x;
|
||||||
|
// Here 'enqueue' takes the RHS ('x'), and the array indices ('i')
|
||||||
|
// as arguments.
|
||||||
|
// - A different version when a partial element update is required,
|
||||||
|
// e.g. for:
|
||||||
|
// logic [31:0] array[N];
|
||||||
|
// for (int i = 0 ; i < N ; ++i) array[i][3:1] <= y;
|
||||||
|
// Here 'enqueue' takes one additional argument, which is a bitmask
|
||||||
|
// derived from the bit selects (_[3:1]), which masks the bits that
|
||||||
|
// need to be updated, and additionally the RHS is widened to a full
|
||||||
|
// element size, with the bits inserted into the masked region.
|
||||||
|
template <typename T_Target, // Type of the variable this commit queue updates
|
||||||
|
bool Partial, // Whether partial element updates are necessary
|
||||||
|
// The following we could figure out from 'T_Target using type traits, but passing
|
||||||
|
// explicitly to avoid template expansion, as Verilator already knows them
|
||||||
|
typename T_Element, // Non-array leaf element type of T_Target array
|
||||||
|
std::size_t T_Rank // Rank of T_Target (i.e.: how many dimensions it has)
|
||||||
|
>
|
||||||
|
class VlNBACommitQueue;
|
||||||
|
|
||||||
|
// Specialization for whole element updates only
|
||||||
|
template <typename T_Target, typename T_Element, std::size_t T_Rank>
|
||||||
|
class VlNBACommitQueue<T_Target, /* Partial: */ false, T_Element, T_Rank> final {
|
||||||
|
// TYPES
|
||||||
|
struct Entry final {
|
||||||
|
T_Element value;
|
||||||
|
size_t indices[T_Rank];
|
||||||
|
};
|
||||||
|
|
||||||
|
// STATE
|
||||||
|
std::vector<Entry> m_pending; // Pending updates, in program order
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CONSTRUCTOR
|
||||||
|
VlNBACommitQueue() = default;
|
||||||
|
VL_UNCOPYABLE(VlNBACommitQueue);
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
template <typename... Args>
|
||||||
|
void enqueue(const T_Element& value, Args... indices) {
|
||||||
|
m_pending.emplace_back(Entry{value, {indices...}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: T_Commit might be different from T_Target. Specifically, when the signal is a
|
||||||
|
// top-level IO port, T_Commit will be a native C array, while T_Target, will be a VlUnpacked
|
||||||
|
template <typename T_Commit>
|
||||||
|
void commit(T_Commit& target) {
|
||||||
|
if (m_pending.empty()) return;
|
||||||
|
for (const Entry& entry : m_pending) {
|
||||||
|
VlApplyIndices<0, T_Rank, T_Commit>::apply(target, entry.indices) = entry.value;
|
||||||
|
}
|
||||||
|
m_pending.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// With partial element updates
|
||||||
|
template <typename T_Target, typename T_Element, std::size_t T_Rank>
|
||||||
|
class VlNBACommitQueue<T_Target, /* Partial: */ true, T_Element, T_Rank> final {
|
||||||
|
// TYPES
|
||||||
|
struct Entry final {
|
||||||
|
T_Element value;
|
||||||
|
T_Element mask;
|
||||||
|
size_t indices[T_Rank];
|
||||||
|
};
|
||||||
|
|
||||||
|
// STATE
|
||||||
|
std::vector<Entry> m_pending; // Pending updates, in program order
|
||||||
|
|
||||||
|
// STATIC METHODS
|
||||||
|
|
||||||
|
// Binary & | ~ for elements to use for masking in partial updates. Sorry for the templates.
|
||||||
|
template <typename T>
|
||||||
|
VL_ATTR_ALWINLINE static typename std::enable_if<!VlIsVlWide<T>::value, T>::type
|
||||||
|
bAnd(const T& a, const T& b) {
|
||||||
|
return a & b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
VL_ATTR_ALWINLINE static typename std::enable_if<VlIsVlWide<T>::value, T>::type
|
||||||
|
bAnd(const T& a, const T& b) {
|
||||||
|
T result;
|
||||||
|
for (size_t i = 0; i < T::Words; ++i) {
|
||||||
|
result.m_storage[i] = a.m_storage[i] & b.m_storage[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
VL_ATTR_ALWINLINE static typename std::enable_if<!VlIsVlWide<T>::value, T>::type
|
||||||
|
bOr(const T& a, const T& b) {
|
||||||
|
return a | b;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
VL_ATTR_ALWINLINE static typename std::enable_if<VlIsVlWide<T>::value, T>::type //
|
||||||
|
bOr(const T& a, const T& b) {
|
||||||
|
T result;
|
||||||
|
for (size_t i = 0; i < T::Words; ++i) {
|
||||||
|
result.m_storage[i] = a.m_storage[i] | b.m_storage[i];
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
VL_ATTR_ALWINLINE static typename std::enable_if<!VlIsVlWide<T>::value, T>::type
|
||||||
|
bNot(const T& a) {
|
||||||
|
return ~a;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
VL_ATTR_ALWINLINE static typename std::enable_if<VlIsVlWide<T>::value, T>::type
|
||||||
|
bNot(const T& a) {
|
||||||
|
T result;
|
||||||
|
for (size_t i = 0; i < T::Words; ++i) result.m_storage[i] = ~a.m_storage[i];
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
// CONSTRUCTOR
|
||||||
|
VlNBACommitQueue() = default;
|
||||||
|
VL_UNCOPYABLE(VlNBACommitQueue);
|
||||||
|
|
||||||
|
// METHODS
|
||||||
|
template <typename... Args>
|
||||||
|
void enqueue(const T_Element& value, const T_Element& mask, Args... indices) {
|
||||||
|
m_pending.emplace_back(Entry{value, mask, {indices...}});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: T_Commit might be different from T_Target. Specifically, when the signal is a
|
||||||
|
// top-level IO port, T_Commit will be a native C array, while T_Target, will be a VlUnpacked
|
||||||
|
template <typename T_Commit>
|
||||||
|
void commit(T_Commit& target) {
|
||||||
|
if (m_pending.empty()) return;
|
||||||
|
for (const Entry& entry : m_pending) { //
|
||||||
|
auto& ref = VlApplyIndices<0, T_Rank, T_Commit>::apply(target, entry.indices);
|
||||||
|
// Maybe inefficient, but it works for now ...
|
||||||
|
const auto oldValue = ref;
|
||||||
|
ref = bOr(bAnd(entry.value, entry.mask), bAnd(oldValue, bNot(entry.mask)));
|
||||||
|
}
|
||||||
|
m_pending.clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
// Object that VlDeleter is capable of deleting
|
// Object that VlDeleter is capable of deleting
|
||||||
|
|
||||||
@@ -1587,12 +1824,16 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//===================================================================
|
//===================================================================
|
||||||
// Represents the null pointer. Used for setting VlClassRef to null instead of
|
// Represents the null pointer. Used for:
|
||||||
// via nullptr_t, to prevent the implicit conversion of 0 to nullptr.
|
// * 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 {
|
struct VlNull final {
|
||||||
operator bool() const { return false; }
|
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
|
// 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) {
|
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) {
|
switch (type) {
|
||||||
|
case VerilatedTracePrefixType::ROOTIO_MODULE:
|
||||||
case VerilatedTracePrefixType::SCOPE_MODULE:
|
case VerilatedTracePrefixType::SCOPE_MODULE:
|
||||||
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
||||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||||
@@ -326,7 +340,9 @@ void VerilatedVcd::pushPrefix(const std::string& name, VerilatedTracePrefixType
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedVcd::popPrefix() {
|
void VerilatedVcd::popPrefix() {
|
||||||
|
assert(!m_prefixStack.empty());
|
||||||
switch (m_prefixStack.back().second) {
|
switch (m_prefixStack.back().second) {
|
||||||
|
case VerilatedTracePrefixType::ROOTIO_MODULE:
|
||||||
case VerilatedTracePrefixType::SCOPE_MODULE:
|
case VerilatedTracePrefixType::SCOPE_MODULE:
|
||||||
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
case VerilatedTracePrefixType::SCOPE_INTERFACE:
|
||||||
case VerilatedTracePrefixType::STRUCT_PACKED:
|
case VerilatedTracePrefixType::STRUCT_PACKED:
|
||||||
@@ -338,7 +354,7 @@ void VerilatedVcd::popPrefix() {
|
|||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
m_prefixStack.pop_back();
|
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,
|
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.
|
// so always inline them.
|
||||||
|
|
||||||
VL_ATTR_ALWINLINE
|
VL_ATTR_ALWINLINE
|
||||||
void VerilatedVcdBuffer::emitEvent(uint32_t code, const VlEventBase* newval) {
|
void VerilatedVcdBuffer::emitEvent(uint32_t code) {
|
||||||
const bool triggered = newval->isTriggered();
|
// Don't prefetch suffix as it's a bit too late;
|
||||||
// TODO : It seems that untriggered events are not filtered
|
char* wp = m_writep;
|
||||||
// should be tested before this last step
|
*wp++ = '1';
|
||||||
if (triggered) {
|
finishLine(code, wp);
|
||||||
// Don't prefetch suffix as it's a bit too late;
|
|
||||||
char* wp = m_writep;
|
|
||||||
*wp++ = '1';
|
|
||||||
finishLine(code, wp);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VL_ATTR_ALWINLINE
|
VL_ATTR_ALWINLINE
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ private:
|
|||||||
friend VerilatedVcdBuffer; // Give the buffer access to the private bits
|
friend VerilatedVcdBuffer; // Give the buffer access to the private bits
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// VCD specific internals
|
// VCD-specific internals
|
||||||
|
|
||||||
VerilatedVcdFile* m_filep; // File we're writing to
|
VerilatedVcdFile* m_filep; // File we're writing to
|
||||||
bool m_fileNewed; // m_filep needs destruction
|
bool m_fileNewed; // m_filep needs destruction
|
||||||
@@ -214,7 +214,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
|
|||||||
// Implementation of VerilatedTraceBuffer interface
|
// Implementation of VerilatedTraceBuffer interface
|
||||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||||
// called from only one place (the full* methods), so always inline them.
|
// 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 emitBit(uint32_t code, CData newval);
|
||||||
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
|
||||||
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);
|
||||||
|
|||||||
+231
-82
@@ -31,11 +31,14 @@
|
|||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
#include "verilated_imp.h"
|
#include "verilated_imp.h"
|
||||||
|
|
||||||
|
#include "vltstd/vpi_user.h"
|
||||||
|
|
||||||
|
#include <cstdarg>
|
||||||
|
#include <cstdio>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_set>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
@@ -630,6 +633,146 @@ public:
|
|||||||
void invalidate() { m_id = 0; }
|
void invalidate() { m_id = 0; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class VerilatedVpiPutHolder final {
|
||||||
|
VerilatedVpioVar m_var;
|
||||||
|
s_vpi_value m_value;
|
||||||
|
union Storage {
|
||||||
|
char init = 0; // to ensure trivial constructor
|
||||||
|
std::string str;
|
||||||
|
std::vector<s_vpi_vecval> vec;
|
||||||
|
~Storage() noexcept {/* handled by VerilatedVpiPutHolder */};
|
||||||
|
} m_storage{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
VerilatedVpiPutHolder(const VerilatedVpioVar* vop, p_vpi_value valuep)
|
||||||
|
: m_var{vop} {
|
||||||
|
m_value.format = valuep->format;
|
||||||
|
switch (valuep->format) {
|
||||||
|
case vpiBinStrVal: // FALLTHRU
|
||||||
|
case vpiOctStrVal: // FALLTHRU
|
||||||
|
case vpiDecStrVal: // FALLTHRU
|
||||||
|
case vpiHexStrVal: // FALLTHRU
|
||||||
|
case vpiStringVal: {
|
||||||
|
new (&m_storage.str) std::string{valuep->value.str};
|
||||||
|
m_value.value.str = const_cast<char*>(m_storage.str.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vpiScalarVal: {
|
||||||
|
m_value.value.scalar = valuep->value.scalar;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vpiIntVal: {
|
||||||
|
m_value.value.integer = valuep->value.integer;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vpiRealVal: {
|
||||||
|
m_value.value.real = valuep->value.real;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vpiVectorVal: {
|
||||||
|
size_t words = 0;
|
||||||
|
switch (vop->varp()->vltype()) {
|
||||||
|
case VLVT_UINT8:
|
||||||
|
case VLVT_UINT16:
|
||||||
|
case VLVT_UINT32: {
|
||||||
|
words = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VLVT_UINT64: {
|
||||||
|
words = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case VLVT_WDATA: {
|
||||||
|
words = VL_WORDS_I(vop->varp()->packed().elements());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
new (&m_storage.vec)
|
||||||
|
std::vector<s_vpi_vecval>{valuep->value.vector, &valuep->value.vector[words]};
|
||||||
|
m_value.value.vector = m_storage.vec.data();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVpiPutHolder(VerilatedVpiPutHolder const& o)
|
||||||
|
: m_var{o.m_var}
|
||||||
|
, m_value{o.m_value} {
|
||||||
|
switch (m_value.format) {
|
||||||
|
case vpiBinStrVal: // FALLTHRU
|
||||||
|
case vpiOctStrVal: // FALLTHRU
|
||||||
|
case vpiDecStrVal: // FALLTHRU
|
||||||
|
case vpiHexStrVal: // FALLTHRU
|
||||||
|
case vpiStringVal: {
|
||||||
|
new (&m_storage.str) std::string{o.m_storage.str};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vpiVectorVal: {
|
||||||
|
new (&m_storage.vec) std::vector<s_vpi_vecval>{o.m_storage.vec};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVpiPutHolder(VerilatedVpiPutHolder&& o) noexcept
|
||||||
|
: m_var{std::move(o.m_var)}
|
||||||
|
, m_value{std::move(o.m_value)} {
|
||||||
|
switch (m_value.format) {
|
||||||
|
case vpiBinStrVal: // FALLTHRU
|
||||||
|
case vpiOctStrVal: // FALLTHRU
|
||||||
|
case vpiDecStrVal: // FALLTHRU
|
||||||
|
case vpiHexStrVal: // FALLTHRU
|
||||||
|
case vpiStringVal: {
|
||||||
|
new (&m_storage.str) std::string{std::move(o.m_storage.str)};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vpiVectorVal: {
|
||||||
|
new (&m_storage.vec) std::vector<s_vpi_vecval>{std::move(o.m_storage.vec)};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
~VerilatedVpiPutHolder() noexcept {
|
||||||
|
switch (m_value.format) {
|
||||||
|
case vpiBinStrVal: // FALLTHRU
|
||||||
|
case vpiOctStrVal: // FALLTHRU
|
||||||
|
case vpiDecStrVal: // FALLTHRU
|
||||||
|
case vpiHexStrVal: // FALLTHRU
|
||||||
|
case vpiStringVal: m_storage.str.~basic_string(); break;
|
||||||
|
case vpiVectorVal: m_storage.vec.~vector(); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
VerilatedVpioVar* varp() { return &m_var; }
|
||||||
|
p_vpi_value valuep() { return &m_value; }
|
||||||
|
|
||||||
|
static bool canInertialDelay(p_vpi_value valuep) {
|
||||||
|
switch (valuep->format) {
|
||||||
|
case vpiBinStrVal: // FALLTHRU
|
||||||
|
case vpiOctStrVal: // FALLTHRU
|
||||||
|
case vpiDecStrVal: // FALLTHRU
|
||||||
|
case vpiHexStrVal: // FALLTHRU
|
||||||
|
case vpiStringVal: {
|
||||||
|
if (VL_UNLIKELY(!valuep->value.str)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case vpiScalarVal: // FALLTHRU
|
||||||
|
case vpiIntVal: // FALLTHRU
|
||||||
|
case vpiRealVal: break;
|
||||||
|
case vpiVectorVal: {
|
||||||
|
if (VL_UNLIKELY(!valuep->value.vector)) return false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
struct VerilatedVpiTimedCbsCmp final {
|
struct VerilatedVpiTimedCbsCmp final {
|
||||||
// Ordering sets keyed by time, then callback unique id
|
// Ordering sets keyed by time, then callback unique id
|
||||||
bool operator()(const std::pair<QData, uint64_t>& a,
|
bool operator()(const std::pair<QData, uint64_t>& a,
|
||||||
@@ -652,9 +795,11 @@ class VerilatedVpiImp final {
|
|||||||
std::array<VpioCbList, CB_ENUM_MAX_VALUE> m_cbCurrentLists;
|
std::array<VpioCbList, CB_ENUM_MAX_VALUE> m_cbCurrentLists;
|
||||||
VpioFutureCbs m_futureCbs; // Time based callbacks for future timestamps
|
VpioFutureCbs m_futureCbs; // Time based callbacks for future timestamps
|
||||||
VpioFutureCbs m_nextCbs; // cbNextSimTime callbacks
|
VpioFutureCbs m_nextCbs; // cbNextSimTime callbacks
|
||||||
|
std::list<VerilatedVpiPutHolder> m_inertialPuts; // Pending vpi puts due to vpiInertialDelay
|
||||||
VerilatedVpiError* m_errorInfop = nullptr; // Container for vpi error info
|
VerilatedVpiError* m_errorInfop = nullptr; // Container for vpi error info
|
||||||
VerilatedAssertOneThread m_assertOne; // Assert only called from single thread
|
VerilatedAssertOneThread m_assertOne; // Assert only called from single thread
|
||||||
uint64_t m_nextCallbackId = 1; // Id to identify callback
|
uint64_t m_nextCallbackId = 1; // Id to identify callback
|
||||||
|
bool m_evalNeeded = false; // Model has had signals updated via vpi_put_value()
|
||||||
|
|
||||||
static VerilatedVpiImp& s() { // Singleton
|
static VerilatedVpiImp& s() { // Singleton
|
||||||
static VerilatedVpiImp s_s;
|
static VerilatedVpiImp s_s;
|
||||||
@@ -751,6 +896,9 @@ public:
|
|||||||
if (VL_LIKELY(it != s().m_futureCbs.cend())) return it->first.first;
|
if (VL_LIKELY(it != s().m_futureCbs.cend())) return it->first.first;
|
||||||
return ~0ULL; // maxquad
|
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 {
|
static bool callCbs(const uint32_t reason) VL_MT_UNSAFE_ONE {
|
||||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: callCbs reason=%u\n", reason););
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: callCbs reason=%u\n", reason););
|
||||||
assertOneCheck();
|
assertOneCheck();
|
||||||
@@ -776,7 +924,7 @@ public:
|
|||||||
assertOneCheck();
|
assertOneCheck();
|
||||||
VpioCbList& cbObjList = s().m_cbCurrentLists[cbValueChange];
|
VpioCbList& cbObjList = s().m_cbCurrentLists[cbValueChange];
|
||||||
bool called = false;
|
bool called = false;
|
||||||
std::unordered_set<VerilatedVpioVar*> update; // set of objects to update after callbacks
|
std::set<VerilatedVpioVar*> update; // set of objects to update after callbacks
|
||||||
if (cbObjList.empty()) return called;
|
if (cbObjList.empty()) return called;
|
||||||
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
|
const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements
|
||||||
for (auto it = cbObjList.begin(); true;) {
|
for (auto it = cbObjList.begin(); true;) {
|
||||||
@@ -813,6 +961,17 @@ public:
|
|||||||
}
|
}
|
||||||
static void dumpCbs() VL_MT_UNSAFE_ONE;
|
static void dumpCbs() VL_MT_UNSAFE_ONE;
|
||||||
static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info
|
static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
static void doInertialPuts() {
|
||||||
|
for (auto& it : s().m_inertialPuts) {
|
||||||
|
vpi_put_value(it.varp()->castVpiHandle(), it.valuep(), nullptr, vpiNoDelay);
|
||||||
|
}
|
||||||
|
s().m_inertialPuts.clear();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
@@ -900,6 +1059,10 @@ bool VerilatedVpi::callCbs(uint32_t reason) VL_MT_UNSAFE_ONE {
|
|||||||
return VerilatedVpiImp::callCbs(reason);
|
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
|
// Historical, before we had multiple kinds of timed callbacks
|
||||||
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callCbs(cbAfterDelay); }
|
void VerilatedVpi::callTimedCbs() VL_MT_UNSAFE_ONE { VerilatedVpiImp::callCbs(cbAfterDelay); }
|
||||||
|
|
||||||
@@ -915,6 +1078,11 @@ PLI_INT32 VerilatedVpioReasonCb::dovpi_remove_cb() {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VerilatedVpi::clearEvalNeeded() VL_MT_UNSAFE_ONE { VerilatedVpiImp::evalNeeded(false); }
|
||||||
|
bool VerilatedVpi::evalNeeded() VL_MT_UNSAFE_ONE { return VerilatedVpiImp::evalNeeded(); }
|
||||||
|
|
||||||
|
void VerilatedVpi::doInertialPuts() VL_MT_UNSAFE_ONE { VerilatedVpiImp::doInertialPuts(); }
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// VerilatedVpiImp implementation
|
// VerilatedVpiImp implementation
|
||||||
|
|
||||||
@@ -2194,13 +2362,28 @@ bool vl_check_format(const VerilatedVar* varp, const p_vpi_value valuep, const c
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void vl_strprintf(std::string& buffer, char const* fmt, ...) {
|
||||||
|
va_list args, args_copy;
|
||||||
|
va_start(args, fmt);
|
||||||
|
buffer.clear();
|
||||||
|
// Make copy of args since we may need to call VL_VSNPRINTF more than once
|
||||||
|
va_copy(args_copy, args);
|
||||||
|
// Try VL_VSNPRINTF in existing buffer
|
||||||
|
const int result
|
||||||
|
= VL_VSNPRINTF(const_cast<char*>(buffer.data()), buffer.capacity(), fmt, args_copy);
|
||||||
|
va_end(args_copy);
|
||||||
|
const int required = result + 1; // Returned size doesn't include NUL terminator
|
||||||
|
// If there wasn't enough space, reallocate and try again
|
||||||
|
if (buffer.capacity() < required) {
|
||||||
|
buffer.reserve(required * 2);
|
||||||
|
VL_VSNPRINTF(const_cast<char*>(buffer.data()), buffer.capacity(), fmt, args);
|
||||||
|
}
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
||||||
const char* fullname) {
|
const char* fullname) {
|
||||||
if (!vl_check_format(varp, valuep, fullname, true)) return;
|
if (!vl_check_format(varp, valuep, fullname, true)) return;
|
||||||
// Maximum required size is for binary string, one byte per bit plus null termination
|
|
||||||
static thread_local char t_outStr[VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE + 1];
|
|
||||||
// cppcheck-suppress variableScope
|
|
||||||
static const thread_local int t_outStrSz = sizeof(t_outStr) - 1;
|
|
||||||
// string data type is dynamic and may vary in size during simulation
|
// string data type is dynamic and may vary in size during simulation
|
||||||
static thread_local std::string t_outDynamicStr;
|
static thread_local std::string t_outDynamicStr;
|
||||||
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
// We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal
|
||||||
@@ -2244,43 +2427,21 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (valuep->format == vpiBinStrVal) {
|
} else if (valuep->format == vpiBinStrVal) {
|
||||||
valuep->value.str = t_outStr;
|
|
||||||
int bits = varp->packed().elements();
|
int bits = varp->packed().elements();
|
||||||
|
t_outDynamicStr.resize(bits);
|
||||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||||
int i;
|
for (size_t i = 0; i < bits; ++i) {
|
||||||
if (bits > t_outStrSz) {
|
|
||||||
// limit maximum size of output to size of buffer to prevent overrun.
|
|
||||||
VL_VPI_WARNING_(
|
|
||||||
__FILE__, __LINE__,
|
|
||||||
"%s: Truncating string value of %s for %s"
|
|
||||||
" as buffer size (%d, VL_VALUE_STRING_MAX_WORDS=%d) is less than required (%d)",
|
|
||||||
__func__, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
|
||||||
VL_VALUE_STRING_MAX_WORDS, bits);
|
|
||||||
bits = t_outStrSz;
|
|
||||||
}
|
|
||||||
for (i = 0; i < bits; ++i) {
|
|
||||||
const char val = (datap[i >> 3] >> (i & 7)) & 1;
|
const char val = (datap[i >> 3] >> (i & 7)) & 1;
|
||||||
t_outStr[bits - i - 1] = val ? '1' : '0';
|
t_outDynamicStr[bits - i - 1] = val ? '1' : '0';
|
||||||
}
|
}
|
||||||
t_outStr[i] = '\0';
|
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||||
return;
|
return;
|
||||||
} else if (valuep->format == vpiOctStrVal) {
|
} else if (valuep->format == vpiOctStrVal) {
|
||||||
valuep->value.str = t_outStr;
|
|
||||||
int chars = (varp->packed().elements() + 2) / 3;
|
int chars = (varp->packed().elements() + 2) / 3;
|
||||||
|
t_outDynamicStr.resize(chars);
|
||||||
const int bytes = VL_BYTES_I(varp->packed().elements());
|
const int bytes = VL_BYTES_I(varp->packed().elements());
|
||||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||||
int i;
|
for (size_t i = 0; i < chars; ++i) {
|
||||||
if (chars > t_outStrSz) {
|
|
||||||
// limit maximum size of output to size of buffer to prevent overrun.
|
|
||||||
VL_VPI_WARNING_(
|
|
||||||
__FILE__, __LINE__,
|
|
||||||
"%s: Truncating string value of %s for %s"
|
|
||||||
" as buffer size (%d, VL_VALUE_STRING_MAX_WORDS=%d) is less than required (%d)",
|
|
||||||
__func__, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
|
||||||
VL_VALUE_STRING_MAX_WORDS, chars);
|
|
||||||
chars = t_outStrSz;
|
|
||||||
}
|
|
||||||
for (i = 0; i < chars; ++i) {
|
|
||||||
const div_t idx = div(i * 3, 8);
|
const div_t idx = div(i * 3, 8);
|
||||||
int val = datap[idx.quot];
|
int val = datap[idx.quot];
|
||||||
if ((idx.quot + 1) < bytes) {
|
if ((idx.quot + 1) < bytes) {
|
||||||
@@ -2299,46 +2460,31 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||||||
val &= (1 << rem) - 1;
|
val &= (1 << rem) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t_outStr[chars - i - 1] = '0' + (val & 7);
|
t_outDynamicStr[chars - i - 1] = '0' + (val & 7);
|
||||||
}
|
}
|
||||||
t_outStr[i] = '\0';
|
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||||
return;
|
return;
|
||||||
} else if (valuep->format == vpiDecStrVal) {
|
} else if (valuep->format == vpiDecStrVal) {
|
||||||
valuep->value.str = t_outStr;
|
|
||||||
// outStrSz does not include nullptr termination so add one
|
|
||||||
if (varp->vltype() == VLVT_UINT8) {
|
if (varp->vltype() == VLVT_UINT8) {
|
||||||
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hhu",
|
vl_strprintf(t_outDynamicStr, "%hhu",
|
||||||
static_cast<unsigned char>(*(reinterpret_cast<CData*>(varDatap))));
|
static_cast<unsigned char>(*(reinterpret_cast<CData*>(varDatap))));
|
||||||
return;
|
|
||||||
} else if (varp->vltype() == VLVT_UINT16) {
|
} else if (varp->vltype() == VLVT_UINT16) {
|
||||||
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hu",
|
vl_strprintf(t_outDynamicStr, "%hu",
|
||||||
static_cast<unsigned short>(*(reinterpret_cast<SData*>(varDatap))));
|
static_cast<unsigned short>(*(reinterpret_cast<SData*>(varDatap))));
|
||||||
return;
|
|
||||||
} else if (varp->vltype() == VLVT_UINT32) {
|
} else if (varp->vltype() == VLVT_UINT32) {
|
||||||
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%u",
|
vl_strprintf(t_outDynamicStr, "%u",
|
||||||
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
|
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
|
||||||
return;
|
|
||||||
} else if (varp->vltype() == VLVT_UINT64) {
|
} else if (varp->vltype() == VLVT_UINT64) {
|
||||||
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%llu",
|
vl_strprintf(t_outDynamicStr, "%llu", // lintok-format-ll
|
||||||
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(varDatap))));
|
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(varDatap))));
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||||
|
return;
|
||||||
} else if (valuep->format == vpiHexStrVal) {
|
} else if (valuep->format == vpiHexStrVal) {
|
||||||
valuep->value.str = t_outStr;
|
|
||||||
int chars = (varp->packed().elements() + 3) >> 2;
|
int chars = (varp->packed().elements() + 3) >> 2;
|
||||||
|
t_outDynamicStr.resize(chars);
|
||||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||||
int i;
|
for (size_t i = 0; i < chars; ++i) {
|
||||||
if (chars > t_outStrSz) {
|
|
||||||
// limit maximum size of output to size of buffer to prevent overrun.
|
|
||||||
VL_VPI_WARNING_(
|
|
||||||
__FILE__, __LINE__,
|
|
||||||
"%s: Truncating string value of %s for %s"
|
|
||||||
" as buffer size (%d, VL_VALUE_STRING_MAX_WORDS=%d) is less than required (%d)",
|
|
||||||
__func__, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz,
|
|
||||||
VL_VALUE_STRING_MAX_WORDS, chars);
|
|
||||||
chars = t_outStrSz;
|
|
||||||
}
|
|
||||||
for (i = 0; i < chars; ++i) {
|
|
||||||
char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15;
|
char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15;
|
||||||
if (i == (chars - 1)) {
|
if (i == (chars - 1)) {
|
||||||
// most significant char, mask off nonexistent bits when vector
|
// most significant char, mask off nonexistent bits when vector
|
||||||
@@ -2349,9 +2495,9 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||||||
val &= (1 << rem) - 1;
|
val &= (1 << rem) - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
t_outStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
|
t_outDynamicStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
|
||||||
}
|
}
|
||||||
t_outStr[i] = '\0';
|
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||||
return;
|
return;
|
||||||
} else if (valuep->format == vpiStringVal) {
|
} else if (valuep->format == vpiStringVal) {
|
||||||
if (varp->vltype() == VLVT_STRING) {
|
if (varp->vltype() == VLVT_STRING) {
|
||||||
@@ -2364,26 +2510,15 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
valuep->value.str = t_outStr;
|
|
||||||
int bytes = VL_BYTES_I(varp->packed().elements());
|
int bytes = VL_BYTES_I(varp->packed().elements());
|
||||||
|
t_outDynamicStr.resize(bytes);
|
||||||
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
const CData* datap = (reinterpret_cast<CData*>(varDatap));
|
||||||
int i;
|
for (size_t i = 0; i < bytes; ++i) {
|
||||||
if (bytes > t_outStrSz) {
|
|
||||||
// limit maximum size of output to size of buffer to prevent overrun.
|
|
||||||
VL_VPI_WARNING_(__FILE__, __LINE__,
|
|
||||||
"%s: Truncating string value of %s for %s"
|
|
||||||
" as buffer size (%d, VL_VALUE_STRING_MAX_WORDS=%d) is less than "
|
|
||||||
"required (%d)",
|
|
||||||
__func__, VerilatedVpiError::strFromVpiVal(valuep->format),
|
|
||||||
fullname, t_outStrSz, VL_VALUE_STRING_MAX_WORDS, bytes);
|
|
||||||
bytes = t_outStrSz;
|
|
||||||
}
|
|
||||||
for (i = 0; i < bytes; ++i) {
|
|
||||||
const char val = datap[bytes - i - 1];
|
const char val = datap[bytes - i - 1];
|
||||||
// other simulators replace [leading?] zero chars with spaces, replicate here.
|
// other simulators replace [leading?] zero chars with spaces, replicate here.
|
||||||
t_outStr[i] = val ? val : ' ';
|
t_outDynamicStr[i] = val ? val : ' ';
|
||||||
}
|
}
|
||||||
t_outStr[i] = '\0';
|
valuep->value.str = const_cast<PLI_BYTE8*>(t_outDynamicStr.c_str());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else if (valuep->format == vpiIntVal) {
|
} else if (valuep->format == vpiIntVal) {
|
||||||
@@ -2432,7 +2567,7 @@ void vpi_get_value(vpiHandle object, p_vpi_value valuep) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_p*/,
|
vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_p*/,
|
||||||
PLI_INT32 /*flags*/) {
|
PLI_INT32 flags) {
|
||||||
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_put_value %p %p\n", object, valuep););
|
VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: vpi_put_value %p %p\n", object, valuep););
|
||||||
VerilatedVpiImp::assertOneCheck();
|
VerilatedVpiImp::assertOneCheck();
|
||||||
VL_VPI_ERROR_RESET_();
|
VL_VPI_ERROR_RESET_();
|
||||||
@@ -2440,11 +2575,24 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||||||
VL_VPI_WARNING_(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer");
|
VL_VPI_WARNING_(__FILE__, __LINE__, "Ignoring vpi_put_value with nullptr value pointer");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
PLI_INT32 delay_mode = flags & 0xfff;
|
||||||
if (const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
|
if (const VerilatedVpioVar* const vop = VerilatedVpioVar::castp(object)) {
|
||||||
|
if (delay_mode == vpiInertialDelay) {
|
||||||
|
if (!VerilatedVpiPutHolder::canInertialDelay(valuep)) {
|
||||||
|
VL_VPI_WARNING_(
|
||||||
|
__FILE__, __LINE__,
|
||||||
|
"%s: Unsupported p_vpi_value as requested for '%s' with vpiInertialDelay",
|
||||||
|
__func__, vop->fullname());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
VerilatedVpiImp::inertialDelay(vop, valuep);
|
||||||
|
return object;
|
||||||
|
}
|
||||||
VL_DEBUG_IF_PLI(
|
VL_DEBUG_IF_PLI(
|
||||||
VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n", vop->fullname(),
|
VL_DBG_MSGF("- vpi: vpi_put_value name=%s fmt=%d vali=%d\n", vop->fullname(),
|
||||||
valuep->format, valuep->value.integer);
|
valuep->format, valuep->value.integer);
|
||||||
VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n", vop->varp()->datap(), vop->varDatap()););
|
VL_DBG_MSGF("- vpi: varp=%p putatp=%p\n", vop->varp()->datap(), vop->varDatap()););
|
||||||
|
VerilatedVpiImp::evalNeeded(true);
|
||||||
|
|
||||||
if (VL_UNLIKELY(!vop->varp()->isPublicRW())) {
|
if (VL_UNLIKELY(!vop->varp()->isPublicRW())) {
|
||||||
VL_VPI_WARNING_(__FILE__, __LINE__,
|
VL_VPI_WARNING_(__FILE__, __LINE__,
|
||||||
@@ -2549,7 +2697,8 @@ vpiHandle vpi_put_value(vpiHandle object, p_vpi_value valuep, p_vpi_time /*time_
|
|||||||
} else if (valuep->format == vpiDecStrVal) {
|
} else if (valuep->format == vpiDecStrVal) {
|
||||||
char remainder[16];
|
char remainder[16];
|
||||||
unsigned long long val;
|
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) {
|
if (success < 1) {
|
||||||
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
|
VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Parsing failed for '%s' as value %s for %s",
|
||||||
__func__, valuep->value.str,
|
__func__, valuep->value.str,
|
||||||
|
|||||||
@@ -49,11 +49,21 @@ public:
|
|||||||
/// Call callbacks of arbitrary types.
|
/// Call callbacks of arbitrary types.
|
||||||
/// User wrapper code should call this from their main loops.
|
/// User wrapper code should call this from their main loops.
|
||||||
static bool callCbs(uint32_t reason) VL_MT_UNSAFE_ONE;
|
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
|
/// Returns time of the next registered VPI callback, or
|
||||||
/// ~(0ULL) if none are registered
|
/// ~(0ULL) if none are registered
|
||||||
static QData cbNextDeadline() VL_MT_UNSAFE_ONE;
|
static QData cbNextDeadline() VL_MT_UNSAFE_ONE;
|
||||||
/// Debug dump of callbacks
|
/// Debug dump of callbacks
|
||||||
static void dumpCbs() VL_MT_UNSAFE_ONE;
|
static void dumpCbs() VL_MT_UNSAFE_ONE;
|
||||||
|
/// Checks VPI dirty state (i.e. whether vpi_put_value() has
|
||||||
|
/// been called since the last clearEvalNeeded())
|
||||||
|
static bool evalNeeded() VL_MT_UNSAFE_ONE;
|
||||||
|
/// Clears VPI dirty state (see evalNeeded())
|
||||||
|
static void clearEvalNeeded() VL_MT_UNSAFE_ONE;
|
||||||
|
/// Perform inertially delayed puts
|
||||||
|
static void doInertialPuts() VL_MT_UNSAFE_ONE;
|
||||||
|
|
||||||
// Self test, for internal use only
|
// Self test, for internal use only
|
||||||
static void selfTest() VL_MT_UNSAFE_ONE;
|
static void selfTest() VL_MT_UNSAFE_ONE;
|
||||||
|
|||||||
+21
-5
@@ -200,6 +200,11 @@
|
|||||||
|
|
||||||
// Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
// Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||||
#define VL_PURE VL_CLANG_ATTR(annotate("PURE"))
|
#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
|
// Comment tag that function is threadsafe
|
||||||
#define VL_MT_SAFE VL_CLANG_ATTR(annotate("MT_SAFE"))
|
#define VL_MT_SAFE VL_CLANG_ATTR(annotate("MT_SAFE"))
|
||||||
// Comment tag that function is threadsafe, only if
|
// Comment tag that function is threadsafe, only if
|
||||||
@@ -216,7 +221,7 @@
|
|||||||
// protected to make sure single-caller
|
// protected to make sure single-caller
|
||||||
#define VL_MT_UNSAFE_ONE VL_CLANG_ATTR(annotate("MT_UNSAFE_ONE"))
|
#define VL_MT_UNSAFE_ONE VL_CLANG_ATTR(annotate("MT_UNSAFE_ONE"))
|
||||||
// Comment tag that function is entry point of parallelization
|
// 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
|
#ifndef VL_NO_LEGACY
|
||||||
# define VL_ULL(c) (c##ULL) // Add appropriate suffix to 64-bit constant (deprecated)
|
# define VL_ULL(c) (c##ULL) // Add appropriate suffix to 64-bit constant (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
|
#define VL_VALUE_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define VL_VALUE_STRING_MAX_CHARS (VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE / VL_BYTESIZE)
|
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Base macros
|
// Base macros
|
||||||
|
|
||||||
@@ -588,9 +591,9 @@ static inline double VL_ROUND(double n) {
|
|||||||
#endif
|
#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
|
#ifndef VL_PORTABLE_ONLY
|
||||||
# ifdef __x86_64__
|
# ifdef __x86_64__
|
||||||
# define VL_X86_64 1
|
# define VL_X86_64 1
|
||||||
@@ -614,8 +617,13 @@ static inline double VL_ROUND(double n) {
|
|||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Time and performance
|
// Time and performance
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
namespace VlOs {
|
namespace VlOs {
|
||||||
|
|
||||||
|
/// Get environment variable
|
||||||
|
extern std::string getenvStr(const std::string& envvar,
|
||||||
|
const std::string& defaultValue) VL_MT_SAFE;
|
||||||
extern uint64_t memUsageBytes() VL_MT_SAFE; ///< Return memory usage in bytes, or 0 if unknown
|
extern uint64_t memUsageBytes() VL_MT_SAFE; ///< Return memory usage in bytes, or 0 if unknown
|
||||||
|
|
||||||
// Internal: Record CPU time, starting point on construction, and current delta from that
|
// Internal: Record CPU time, starting point on construction, and current delta from that
|
||||||
@@ -648,6 +656,14 @@ public:
|
|||||||
return (m_start == 0.0) ? 0.0 : gettime() - m_start;
|
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
|
} //namespace VlOs
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
|
|||||||
+30
-4
@@ -51,10 +51,10 @@ double DeltaCpuTime::gettime() VL_MT_SAFE {
|
|||||||
#else
|
#else
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||||
timespec ts;
|
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;
|
return ts.tv_sec + ts.tv_nsec * 1e-9;
|
||||||
#endif
|
#endif
|
||||||
return 0.0;
|
return 0.0; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
double DeltaWallTime::gettime() VL_MT_SAFE {
|
double DeltaWallTime::gettime() VL_MT_SAFE {
|
||||||
#if defined(_WIN32) || defined(__MINGW32__)
|
#if defined(_WIN32) || defined(__MINGW32__)
|
||||||
@@ -66,9 +66,9 @@ double DeltaWallTime::gettime() VL_MT_SAFE {
|
|||||||
#else
|
#else
|
||||||
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init)
|
||||||
timespec ts;
|
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 ts.tv_sec + ts.tv_nsec * 1e-9;
|
||||||
return 0.0;
|
return 0.0; // LCOV_EXCL_LINE
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,5 +99,31 @@ uint64_t memUsageBytes() VL_MT_SAFE {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//=========================================================================
|
||||||
|
// VlOs::getenvStr implementation
|
||||||
|
|
||||||
|
std::string getenvStr(const std::string& envvar, const std::string& defaultValue) VL_MT_SAFE {
|
||||||
|
std::string ret;
|
||||||
|
#if defined(_MSC_VER)
|
||||||
|
// Note: MinGW does not offer _dupenv_s
|
||||||
|
const char* envvalue = nullptr;
|
||||||
|
_dupenv_s((char**)&envvalue, nullptr, envvar.c_str());
|
||||||
|
if (envvalue != nullptr) {
|
||||||
|
const std::string result{envvalue};
|
||||||
|
free((void*)envvalue);
|
||||||
|
ret = result;
|
||||||
|
} else {
|
||||||
|
ret = defaultValue;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (const char* const envvalue = getenv(envvar.c_str())) {
|
||||||
|
ret = envvalue;
|
||||||
|
} else {
|
||||||
|
ret = defaultValue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
} //namespace VlOs
|
} //namespace VlOs
|
||||||
|
|||||||
+165
-222
@@ -48,9 +48,11 @@ def fully_qualified_name(node):
|
|||||||
if node.kind == CursorKind.TRANSLATION_UNIT:
|
if node.kind == CursorKind.TRANSLATION_UNIT:
|
||||||
return []
|
return []
|
||||||
res = fully_qualified_name(node.semantic_parent)
|
res = fully_qualified_name(node.semantic_parent)
|
||||||
|
displayname = node.displayname
|
||||||
|
displayname = [displayname] if displayname else []
|
||||||
if res:
|
if res:
|
||||||
return res + ([node.displayname] if node.displayname else [])
|
return res + displayname
|
||||||
return [node.displayname] if node.displayname else []
|
return displayname
|
||||||
|
|
||||||
|
|
||||||
# Returns True, if `class_node` contains node
|
# Returns True, if `class_node` contains node
|
||||||
@@ -106,9 +108,8 @@ class VlAnnotations:
|
|||||||
|
|
||||||
def is_mt_safe_call(self):
|
def is_mt_safe_call(self):
|
||||||
return (not self.is_mt_unsafe_call()
|
return (not self.is_mt_unsafe_call()
|
||||||
and (self.mt_safe or self.mt_safe_postinit or self.pure
|
and (self.mt_safe or self.mt_safe_postinit or self.pure or self.requires
|
||||||
or self.requires or self.excludes or self.acquire
|
or self.excludes or self.acquire or self.release))
|
||||||
or self.release))
|
|
||||||
|
|
||||||
def is_pure_call(self):
|
def is_pure_call(self):
|
||||||
return self.pure
|
return self.pure
|
||||||
@@ -140,31 +141,32 @@ class VlAnnotations:
|
|||||||
result = VlAnnotations()
|
result = VlAnnotations()
|
||||||
for node in nodes:
|
for node in nodes:
|
||||||
if node.kind == CursorKind.ANNOTATE_ATTR:
|
if node.kind == CursorKind.ANNOTATE_ATTR:
|
||||||
if node.displayname == "MT_START":
|
displayname = node.displayname
|
||||||
|
if displayname == "MT_START":
|
||||||
result.mt_start = True
|
result.mt_start = True
|
||||||
elif node.displayname == "MT_SAFE":
|
elif displayname == "MT_SAFE":
|
||||||
result.mt_safe = True
|
result.mt_safe = True
|
||||||
elif node.displayname == "MT_STABLE":
|
elif displayname == "MT_STABLE":
|
||||||
result.stable_tree = True
|
result.stable_tree = True
|
||||||
elif node.displayname == "MT_SAFE_POSTINIT":
|
elif displayname == "MT_SAFE_POSTINIT":
|
||||||
result.mt_safe_postinit = True
|
result.mt_safe_postinit = True
|
||||||
elif node.displayname == "MT_UNSAFE":
|
elif displayname == "MT_UNSAFE":
|
||||||
result.mt_unsafe = True
|
result.mt_unsafe = True
|
||||||
elif node.displayname == "MT_UNSAFE_ONE":
|
elif displayname == "MT_UNSAFE_ONE":
|
||||||
result.mt_unsafe_one = True
|
result.mt_unsafe_one = True
|
||||||
elif node.displayname == "MT_DISABLED":
|
elif displayname == "MT_DISABLED":
|
||||||
result.mt_disabled = True
|
result.mt_disabled = True
|
||||||
elif node.displayname == "PURE":
|
elif displayname == "PURE":
|
||||||
result.pure = True
|
result.pure = True
|
||||||
elif node.displayname in ["ACQUIRE", "ACQUIRE_SHARED"]:
|
elif displayname in ["ACQUIRE", "ACQUIRE_SHARED"]:
|
||||||
result.acquire = True
|
result.acquire = True
|
||||||
elif node.displayname in ["RELEASE", "RELEASE_SHARED"]:
|
elif displayname in ["RELEASE", "RELEASE_SHARED"]:
|
||||||
result.release = True
|
result.release = True
|
||||||
elif node.displayname == "REQUIRES":
|
elif displayname == "REQUIRES":
|
||||||
result.requires = True
|
result.requires = True
|
||||||
elif node.displayname in ["EXCLUDES", "MT_SAFE_EXCLUDES"]:
|
elif displayname in ["EXCLUDES", "MT_SAFE_EXCLUDES"]:
|
||||||
result.excludes = True
|
result.excludes = True
|
||||||
elif node.displayname == "GUARDED_BY":
|
elif displayname == "GUARDED_BY":
|
||||||
result.guarded = True
|
result.guarded = True
|
||||||
# Attributes are always at the beginning
|
# Attributes are always at the beginning
|
||||||
elif not node.kind.is_attribute():
|
elif not node.kind.is_attribute():
|
||||||
@@ -203,9 +205,7 @@ class FunctionInfo:
|
|||||||
annotations: VlAnnotations
|
annotations: VlAnnotations
|
||||||
ftype: FunctionType
|
ftype: FunctionType
|
||||||
|
|
||||||
_hash: Optional[int] = dataclasses.field(default=None,
|
_hash: Optional[int] = dataclasses.field(default=None, init=False, repr=False)
|
||||||
init=False,
|
|
||||||
repr=False)
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def name(self):
|
def name(self):
|
||||||
@@ -220,15 +220,13 @@ class FunctionInfo:
|
|||||||
return self._hash
|
return self._hash
|
||||||
|
|
||||||
def __eq__(self, other):
|
def __eq__(self, other):
|
||||||
return (self.usr == other.usr and self.file == other.file
|
return (self.usr == other.usr and self.file == other.file and self.line == other.line)
|
||||||
and self.line == other.line)
|
|
||||||
|
|
||||||
def copy(self, /, **changes):
|
def copy(self, /, **changes):
|
||||||
return dataclasses.replace(self, **changes)
|
return dataclasses.replace(self, **changes)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def from_decl_file_line_and_refd_node(file: str, line: int,
|
def from_decl_file_line_and_refd_node(file: str, line: int, refd: clang.cindex.Cursor,
|
||||||
refd: clang.cindex.Cursor,
|
|
||||||
annotations: VlAnnotations):
|
annotations: VlAnnotations):
|
||||||
file = os.path.abspath(file)
|
file = os.path.abspath(file)
|
||||||
refd = refd.canonical
|
refd = refd.canonical
|
||||||
@@ -277,14 +275,11 @@ class Diagnostic:
|
|||||||
source_ctx: FunctionInfo
|
source_ctx: FunctionInfo
|
||||||
kind: DiagnosticKind
|
kind: DiagnosticKind
|
||||||
|
|
||||||
_hash: Optional[int] = dataclasses.field(default=None,
|
_hash: Optional[int] = dataclasses.field(default=None, init=False, repr=False)
|
||||||
init=False,
|
|
||||||
repr=False)
|
|
||||||
|
|
||||||
def __hash__(self):
|
def __hash__(self):
|
||||||
if not self._hash:
|
if not self._hash:
|
||||||
self._hash = hash(
|
self._hash = hash(hash(self.target) ^ hash(self.source_ctx) ^ hash(self.kind))
|
||||||
hash(self.target) ^ hash(self.source_ctx) ^ hash(self.kind))
|
|
||||||
return self._hash
|
return self._hash
|
||||||
|
|
||||||
|
|
||||||
@@ -292,9 +287,9 @@ class CallAnnotationsValidator:
|
|||||||
|
|
||||||
def __init__(self, diagnostic_cb: Callable[[Diagnostic], None],
|
def __init__(self, diagnostic_cb: Callable[[Diagnostic], None],
|
||||||
is_ignored_top_level: Callable[[clang.cindex.Cursor], bool],
|
is_ignored_top_level: Callable[[clang.cindex.Cursor], bool],
|
||||||
is_ignored_def: Callable[
|
is_ignored_def: Callable[[clang.cindex.Cursor, clang.cindex.Cursor],
|
||||||
[clang.cindex.Cursor, clang.cindex.Cursor], bool],
|
bool], is_ignored_call: Callable[[clang.cindex.Cursor],
|
||||||
is_ignored_call: Callable[[clang.cindex.Cursor], bool]):
|
bool]):
|
||||||
self._diagnostic_cb = diagnostic_cb
|
self._diagnostic_cb = diagnostic_cb
|
||||||
self._is_ignored_top_level = is_ignored_top_level
|
self._is_ignored_top_level = is_ignored_top_level
|
||||||
self._is_ignored_call = is_ignored_call
|
self._is_ignored_call = is_ignored_call
|
||||||
@@ -312,6 +307,7 @@ class CallAnnotationsValidator:
|
|||||||
self._defines: dict[str, str] = {}
|
self._defines: dict[str, str] = {}
|
||||||
self._call_location: Optional[FunctionInfo] = None
|
self._call_location: Optional[FunctionInfo] = None
|
||||||
self._caller: 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._constructor_context: list[clang.cindex.Cursor] = []
|
||||||
self._level: int = 0
|
self._level: int = 0
|
||||||
|
|
||||||
@@ -329,8 +325,7 @@ class CallAnnotationsValidator:
|
|||||||
with open(source_file, "r", encoding="utf-8") as file:
|
with open(source_file, "r", encoding="utf-8") as file:
|
||||||
for line in file:
|
for line in file:
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
match = re.fullmatch(
|
match = re.fullmatch(r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line)
|
||||||
r"^#\s*(define\s+(\w+)(?:\s+(.*))?|include\s+.*)$", line)
|
|
||||||
if match:
|
if match:
|
||||||
if match.group(1).startswith("define"):
|
if match.group(1).startswith("define"):
|
||||||
key = match.group(2)
|
key = match.group(2)
|
||||||
@@ -341,16 +336,14 @@ class CallAnnotationsValidator:
|
|||||||
return defs
|
return defs
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def filter_out_unsupported_compiler_args(
|
def filter_out_unsupported_compiler_args(args: list[str]) -> tuple[list[str], dict[str, str]]:
|
||||||
args: list[str]) -> tuple[list[str], dict[str, str]]:
|
|
||||||
filtered_args = []
|
filtered_args = []
|
||||||
defines = {}
|
defines = {}
|
||||||
args_iter = iter(args)
|
args_iter = iter(args)
|
||||||
try:
|
try:
|
||||||
while arg := next(args_iter):
|
while arg := next(args_iter):
|
||||||
# Skip positional arguments (input file name).
|
# Skip positional arguments (input file name).
|
||||||
if not arg.startswith("-") and (arg.endswith(".cpp")
|
if not arg.startswith("-") and (arg.endswith(".cpp") or arg.endswith(".c")
|
||||||
or arg.endswith(".c")
|
|
||||||
or arg.endswith(".h")):
|
or arg.endswith(".h")):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
@@ -367,8 +360,7 @@ class CallAnnotationsValidator:
|
|||||||
# Preserved options with separate value argument.
|
# Preserved options with separate value argument.
|
||||||
if arg in [
|
if arg in [
|
||||||
"-x"
|
"-x"
|
||||||
"-Xclang", "-I", "-isystem", "-iquote", "-include",
|
"-Xclang", "-I", "-isystem", "-iquote", "-include", "-include-pch"
|
||||||
"-include-pch"
|
|
||||||
]:
|
]:
|
||||||
filtered_args += [arg, next(args_iter)]
|
filtered_args += [arg, next(args_iter)]
|
||||||
continue
|
continue
|
||||||
@@ -406,14 +398,12 @@ class CallAnnotationsValidator:
|
|||||||
|
|
||||||
return (filtered_args, defines)
|
return (filtered_args, defines)
|
||||||
|
|
||||||
def compile_and_analyze_file(self, source_file: str,
|
def compile_and_analyze_file(self, source_file: str, compiler_args: list[str],
|
||||||
compiler_args: list[str],
|
|
||||||
build_dir: Optional[str]):
|
build_dir: Optional[str]):
|
||||||
filename = os.path.abspath(source_file)
|
filename = os.path.abspath(source_file)
|
||||||
initial_cwd = "."
|
initial_cwd = "."
|
||||||
|
|
||||||
filtered_args, defines = self.filter_out_unsupported_compiler_args(
|
filtered_args, defines = self.filter_out_unsupported_compiler_args(compiler_args)
|
||||||
compiler_args)
|
|
||||||
defines.update(self.parse_initial_defines(source_file))
|
defines.update(self.parse_initial_defines(source_file))
|
||||||
|
|
||||||
if build_dir:
|
if build_dir:
|
||||||
@@ -451,8 +441,7 @@ class CallAnnotationsValidator:
|
|||||||
self._diagnostic_cb(Diagnostic(target, source, source_ctx, kind))
|
self._diagnostic_cb(Diagnostic(target, source, source_ctx, kind))
|
||||||
else:
|
else:
|
||||||
self._diagnostic_cb(
|
self._diagnostic_cb(
|
||||||
Diagnostic(FunctionInfo.from_node(target), source, source_ctx,
|
Diagnostic(FunctionInfo.from_node(target), source, source_ctx, kind))
|
||||||
kind))
|
|
||||||
|
|
||||||
def iterate_children(self, children: Iterable[clang.cindex.Cursor],
|
def iterate_children(self, children: Iterable[clang.cindex.Cursor],
|
||||||
handler: Callable[[clang.cindex.Cursor], None]):
|
handler: Callable[[clang.cindex.Cursor], None]):
|
||||||
@@ -465,8 +454,7 @@ class CallAnnotationsValidator:
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def get_referenced_node_info(
|
def get_referenced_node_info(
|
||||||
node: clang.cindex.Cursor
|
node: clang.cindex.Cursor
|
||||||
) -> tuple[bool, Optional[clang.cindex.Cursor], VlAnnotations,
|
) -> tuple[bool, Optional[clang.cindex.Cursor], VlAnnotations, Iterable[clang.cindex.Cursor]]:
|
||||||
Iterable[clang.cindex.Cursor]]:
|
|
||||||
if not node.spelling and not node.displayname:
|
if not node.spelling and not node.displayname:
|
||||||
return (False, None, VlAnnotations(), [])
|
return (False, None, VlAnnotations(), [])
|
||||||
|
|
||||||
@@ -480,8 +468,7 @@ class CallAnnotationsValidator:
|
|||||||
annotations = VlAnnotations.from_nodes_list(children)
|
annotations = VlAnnotations.from_nodes_list(children)
|
||||||
return (True, refd, annotations, children)
|
return (True, refd, annotations, children)
|
||||||
|
|
||||||
def check_mt_safe_call(self, node: clang.cindex.Cursor,
|
def check_mt_safe_call(self, node: clang.cindex.Cursor, refd: clang.cindex.Cursor,
|
||||||
refd: clang.cindex.Cursor,
|
|
||||||
annotations: VlAnnotations):
|
annotations: VlAnnotations):
|
||||||
is_mt_safe = False
|
is_mt_safe = False
|
||||||
|
|
||||||
@@ -513,8 +500,7 @@ class CallAnnotationsValidator:
|
|||||||
# we are calling local method. It is MT safe
|
# we are calling local method. It is MT safe
|
||||||
# only if this method is also only calling local methods or
|
# only if this method is also only calling local methods or
|
||||||
# MT-safe methods
|
# MT-safe methods
|
||||||
self.iterate_children(refd.get_children(),
|
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||||
self.dispatch_node_inside_definition)
|
|
||||||
is_mt_safe = True
|
is_mt_safe = True
|
||||||
# class/struct member
|
# class/struct member
|
||||||
elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced:
|
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:
|
if self.is_constructor_context() and refn.semantic_parent:
|
||||||
# we are in constructor, so calling local members is MT_SAFE,
|
# we are in constructor, so calling local members is MT_SAFE,
|
||||||
# make sure object that we are calling is local to the constructor
|
# make sure object that we are calling is local to the constructor
|
||||||
constructor_class = self._constructor_context[
|
constructor_class = self._constructor_context[-1].semantic_parent
|
||||||
-1].semantic_parent
|
|
||||||
if refn.semantic_parent.spelling == constructor_class.spelling:
|
if refn.semantic_parent.spelling == constructor_class.spelling:
|
||||||
if check_class_member_exists(constructor_class, refn):
|
if check_class_member_exists(constructor_class, refn):
|
||||||
is_mt_safe = True
|
is_mt_safe = True
|
||||||
else:
|
else:
|
||||||
# check if this class inherits from some base class
|
# check if this class inherits from some base class
|
||||||
base_class = get_base_class(constructor_class,
|
base_class = get_base_class(constructor_class, refn.semantic_parent)
|
||||||
refn.semantic_parent)
|
|
||||||
if base_class:
|
if base_class:
|
||||||
if check_class_member_exists(
|
if check_class_member_exists(base_class.get_declaration(), refn):
|
||||||
base_class.get_declaration(), refn):
|
|
||||||
is_mt_safe = True
|
is_mt_safe = True
|
||||||
# variable
|
# variable
|
||||||
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
|
elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced:
|
||||||
@@ -567,8 +550,7 @@ class CallAnnotationsValidator:
|
|||||||
|
|
||||||
# Call handling
|
# Call handling
|
||||||
|
|
||||||
def process_method_call(self, node: clang.cindex.Cursor,
|
def process_method_call(self, node: clang.cindex.Cursor, refd: clang.cindex.Cursor,
|
||||||
refd: clang.cindex.Cursor,
|
|
||||||
annotations: VlAnnotations):
|
annotations: VlAnnotations):
|
||||||
assert self._call_location
|
assert self._call_location
|
||||||
ctx = self._call_location.annotations
|
ctx = self._call_location.annotations
|
||||||
@@ -576,58 +558,48 @@ class CallAnnotationsValidator:
|
|||||||
# MT-safe context
|
# MT-safe context
|
||||||
if ctx.is_mt_safe_context():
|
if ctx.is_mt_safe_context():
|
||||||
if not self.check_mt_safe_call(node, refd, annotations):
|
if not self.check_mt_safe_call(node, refd, annotations):
|
||||||
self.emit_diagnostic(
|
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
|
||||||
|
|
||||||
# stable tree context
|
# stable tree context
|
||||||
if ctx.is_stabe_tree_context():
|
if ctx.is_stabe_tree_context():
|
||||||
if annotations.is_mt_unsafe_call() or not (
|
if annotations.is_mt_unsafe_call() or not (
|
||||||
annotations.is_stabe_tree_call()
|
annotations.is_stabe_tree_call() or annotations.is_pure_call()
|
||||||
or annotations.is_pure_call()
|
|
||||||
or self.check_mt_safe_call(node, refd, annotations)):
|
or self.check_mt_safe_call(node, refd, annotations)):
|
||||||
self.emit_diagnostic(
|
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
|
||||||
|
|
||||||
# pure context
|
# pure context
|
||||||
if ctx.is_pure_context():
|
if ctx.is_pure_context():
|
||||||
if not annotations.is_pure_call():
|
if not annotations.is_pure_call():
|
||||||
self.emit_diagnostic(
|
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
|
||||||
|
|
||||||
def process_function_call(self, refd: clang.cindex.Cursor,
|
def process_function_call(self, refd: clang.cindex.Cursor, annotations: VlAnnotations):
|
||||||
annotations: VlAnnotations):
|
|
||||||
assert self._call_location
|
assert self._call_location
|
||||||
ctx = self._call_location.annotations
|
ctx = self._call_location.annotations
|
||||||
|
|
||||||
# MT-safe context
|
# MT-safe context
|
||||||
if ctx.is_mt_safe_context():
|
if ctx.is_mt_safe_context():
|
||||||
if not annotations.is_mt_safe_call():
|
if not annotations.is_mt_safe_call():
|
||||||
self.emit_diagnostic(
|
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
||||||
DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX)
|
|
||||||
|
|
||||||
# stable tree context
|
# stable tree context
|
||||||
if ctx.is_stabe_tree_context():
|
if ctx.is_stabe_tree_context():
|
||||||
if annotations.is_mt_unsafe_call() or not (
|
if annotations.is_mt_unsafe_call() or not (annotations.is_pure_call()
|
||||||
annotations.is_pure_call()
|
or annotations.is_mt_safe_call()
|
||||||
or annotations.is_mt_safe_call()
|
or annotations.is_stabe_tree_call()):
|
||||||
or annotations.is_stabe_tree_call()):
|
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||||
self.emit_diagnostic(
|
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
|
||||||
DiagnosticKind.NON_STABLE_TREE_CALL_IN_STABLE_TREE_CTX)
|
|
||||||
|
|
||||||
# pure context
|
# pure context
|
||||||
if ctx.is_pure_context():
|
if ctx.is_pure_context():
|
||||||
if not annotations.is_pure_call():
|
if not annotations.is_pure_call():
|
||||||
self.emit_diagnostic(
|
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
|
||||||
|
|
||||||
def process_constructor_call(self, refd: clang.cindex.Cursor,
|
def process_constructor_call(self, refd: clang.cindex.Cursor, annotations: VlAnnotations):
|
||||||
annotations: VlAnnotations):
|
|
||||||
assert self._call_location
|
assert self._call_location
|
||||||
ctx = self._call_location.annotations
|
ctx = self._call_location.annotations
|
||||||
|
|
||||||
@@ -635,31 +607,26 @@ class CallAnnotationsValidator:
|
|||||||
# only if they call local methods or MT-safe functions.
|
# only if they call local methods or MT-safe functions.
|
||||||
if ctx.is_mt_safe_context() or self.is_constructor_context():
|
if ctx.is_mt_safe_context() or self.is_constructor_context():
|
||||||
self._constructor_context.append(refd)
|
self._constructor_context.append(refd)
|
||||||
self.iterate_children(refd.get_children(),
|
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||||
self.dispatch_node_inside_definition)
|
|
||||||
self._constructor_context.pop()
|
self._constructor_context.pop()
|
||||||
|
|
||||||
# stable tree context
|
# stable tree context
|
||||||
if ctx.is_stabe_tree_context():
|
if ctx.is_stabe_tree_context():
|
||||||
self._constructor_context.append(refd)
|
self._constructor_context.append(refd)
|
||||||
self.iterate_children(refd.get_children(),
|
self.iterate_children(refd.get_children(), self.dispatch_node_inside_definition)
|
||||||
self.dispatch_node_inside_definition)
|
|
||||||
self._constructor_context.pop()
|
self._constructor_context.pop()
|
||||||
|
|
||||||
# pure context
|
# pure context
|
||||||
if ctx.is_pure_context():
|
if ctx.is_pure_context():
|
||||||
if not annotations.is_pure_call(
|
if not annotations.is_pure_call() and not refd.is_default_constructor():
|
||||||
) and not refd.is_default_constructor():
|
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||||
self.emit_diagnostic(
|
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
|
||||||
DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX)
|
|
||||||
|
|
||||||
def dispatch_call_node(self, node: clang.cindex.Cursor):
|
def dispatch_call_node(self, node: clang.cindex.Cursor):
|
||||||
[supported, refd, annotations, _] = self.get_referenced_node_info(node)
|
[supported, refd, annotations, _] = self.get_referenced_node_info(node)
|
||||||
|
|
||||||
if not supported:
|
if not supported:
|
||||||
self.iterate_children(node.get_children(),
|
self.iterate_children(node.get_children(), self.dispatch_node_inside_definition)
|
||||||
self.dispatch_node_inside_definition)
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
assert refd is not None
|
assert refd is not None
|
||||||
@@ -676,19 +643,14 @@ class CallAnnotationsValidator:
|
|||||||
|
|
||||||
assert self._call_location is not None
|
assert self._call_location is not None
|
||||||
node_file = os.path.abspath(node.location.file.name)
|
node_file = os.path.abspath(node.location.file.name)
|
||||||
self._call_location = self._call_location.copy(file=node_file,
|
self._call_location = self._call_location.copy(file=node_file, line=node.location.line)
|
||||||
line=node.location.line)
|
|
||||||
|
|
||||||
# Standalone functions and static class methods
|
# Standalone functions and static class methods
|
||||||
if (refd.kind == CursorKind.FUNCTION_DECL
|
if (refd.kind == CursorKind.FUNCTION_DECL
|
||||||
or refd.kind == CursorKind.CXX_METHOD
|
or refd.kind == CursorKind.CXX_METHOD and refd.is_static_method()):
|
||||||
and refd.is_static_method()):
|
|
||||||
self.process_function_call(refd, annotations)
|
self.process_function_call(refd, annotations)
|
||||||
# Function pointer
|
# Function pointer
|
||||||
elif refd.kind in [
|
elif refd.kind in [CursorKind.VAR_DECL, CursorKind.FIELD_DECL, CursorKind.PARM_DECL]:
|
||||||
CursorKind.VAR_DECL, CursorKind.FIELD_DECL,
|
|
||||||
CursorKind.PARM_DECL
|
|
||||||
]:
|
|
||||||
self.process_function_call(refd, annotations)
|
self.process_function_call(refd, annotations)
|
||||||
# Non-static class methods
|
# Non-static class methods
|
||||||
elif refd.kind == CursorKind.CXX_METHOD:
|
elif refd.kind == CursorKind.CXX_METHOD:
|
||||||
@@ -726,18 +688,25 @@ class CallAnnotationsValidator:
|
|||||||
if self.dispatch_call_node(node) is False:
|
if self.dispatch_call_node(node) is False:
|
||||||
return None
|
return None
|
||||||
elif node.is_definition() and node.kind in [
|
elif node.is_definition() and node.kind in [
|
||||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
|
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL, CursorKind.CONSTRUCTOR,
|
||||||
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
|
CursorKind.CONVERSION_FUNCTION
|
||||||
]:
|
]:
|
||||||
self.process_function_definition(node)
|
self.process_function_definition(node)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return self.iterate_children(node.get_children(),
|
return self.iterate_children(node.get_children(), self.dispatch_node_inside_definition)
|
||||||
self.dispatch_node_inside_definition)
|
|
||||||
|
|
||||||
def process_function_definition(self, node: clang.cindex.Cursor):
|
def process_function_definition(self, node: clang.cindex.Cursor):
|
||||||
[supported, refd, annotations, _] = self.get_referenced_node_info(node)
|
[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):
|
if refd and self._is_ignored_def(node, refd):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
@@ -752,30 +721,29 @@ class CallAnnotationsValidator:
|
|||||||
# Implicitly mark definitions in VL_MT_DISABLED_CODE_UNIT .cpp files as
|
# Implicitly mark definitions in VL_MT_DISABLED_CODE_UNIT .cpp files as
|
||||||
# VL_MT_DISABLED. Existence of the annotation on declarations in .h
|
# VL_MT_DISABLED. Existence of the annotation on declarations in .h
|
||||||
# files is verified below.
|
# 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.
|
# explicit VL_MT_DISABLED.
|
||||||
if self.is_mt_disabled_code_unit():
|
if self.is_mt_disabled_code_unit():
|
||||||
if node.location.file.name == self._main_source_file:
|
if node.location.file.name == self._main_source_file:
|
||||||
annotations.mt_disabled = True
|
annotations.mt_disabled = True
|
||||||
annotations.requires = True
|
annotations.excludes = True
|
||||||
if refd.location.file.name == self._main_source_file:
|
if refd.location.file.name == self._main_source_file:
|
||||||
def_annotations.mt_disabled = True
|
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
|
# Use definition's annotations for the diagnostic
|
||||||
# source (i.e. the definition)
|
# source (i.e. the definition)
|
||||||
self._caller = FunctionInfo.from_node(node, refd, def_annotations)
|
self._caller = FunctionInfo.from_node(node, refd, def_annotations)
|
||||||
self._call_location = self._caller
|
self._call_location = self._caller
|
||||||
|
|
||||||
self.emit_diagnostic(
|
self.emit_diagnostic(FunctionInfo.from_node(refd, refd, annotations),
|
||||||
FunctionInfo.from_node(refd, refd, annotations),
|
DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH)
|
||||||
DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH)
|
|
||||||
|
|
||||||
# Use concatenation of definition and declaration annotations
|
else:
|
||||||
# for calls validation.
|
# Use concatenation of definition and declaration annotations
|
||||||
self._caller = FunctionInfo.from_node(node, refd,
|
# for calls validation.
|
||||||
def_annotations | annotations)
|
self._caller = FunctionInfo.from_node(node, refd, def_annotations | annotations)
|
||||||
prev_call_location = self._call_location
|
prev_call_location = self._call_location
|
||||||
self._call_location = self._caller
|
self._call_location = self._caller
|
||||||
|
|
||||||
@@ -793,8 +761,7 @@ class CallAnnotationsValidator:
|
|||||||
if declarations:
|
if declarations:
|
||||||
del self._external_decls[usr]
|
del self._external_decls[usr]
|
||||||
|
|
||||||
self.iterate_children(node_children,
|
self.iterate_children(node_children, self.dispatch_node_inside_definition)
|
||||||
self.dispatch_node_inside_definition)
|
|
||||||
|
|
||||||
self._call_location = prev_call_location
|
self._call_location = prev_call_location
|
||||||
self._caller = prev_call_location
|
self._caller = prev_call_location
|
||||||
@@ -804,25 +771,37 @@ class CallAnnotationsValidator:
|
|||||||
# Nodes not located inside definition
|
# Nodes not located inside definition
|
||||||
|
|
||||||
def dispatch_node(self, node: clang.cindex.Cursor):
|
def dispatch_node(self, node: clang.cindex.Cursor):
|
||||||
if node.kind in [
|
kind = node.kind
|
||||||
CursorKind.CXX_METHOD, CursorKind.FUNCTION_DECL,
|
if kind is CursorKind.CXX_BASE_SPECIFIER:
|
||||||
CursorKind.CONSTRUCTOR, CursorKind.CONVERSION_FUNCTION
|
# 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():
|
if node.is_definition():
|
||||||
return self.process_function_definition(node)
|
return self.process_function_definition(node)
|
||||||
# else:
|
|
||||||
return self.process_function_declaration(node)
|
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(
|
# Clean declarations if class declaration processing is finished.
|
||||||
self, translation_unit: clang.cindex.TranslationUnit):
|
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
|
self._level += 1
|
||||||
kv_defines = sorted([f"{k}={v}" for k, v in self._defines.items()])
|
kv_defines = sorted([f"{k}={v}" for k, v in self._defines.items()])
|
||||||
concat_defines = '\n'.join(kv_defines)
|
concat_defines = '\n'.join(kv_defines)
|
||||||
# List of headers already processed in a TU with specified set of defines.
|
# List of headers already processed in a TU with specified set of defines.
|
||||||
tu_processed_headers = self._processed_headers.setdefault(
|
tu_processed_headers = self._processed_headers.setdefault(concat_defines, set())
|
||||||
concat_defines, set())
|
|
||||||
for child in translation_unit.cursor.get_children():
|
for child in translation_unit.cursor.get_children():
|
||||||
if self._is_ignored_top_level(child):
|
if self._is_ignored_top_level(child):
|
||||||
continue
|
continue
|
||||||
@@ -833,10 +812,8 @@ class CallAnnotationsValidator:
|
|||||||
self.dispatch_node(child)
|
self.dispatch_node(child)
|
||||||
self._level -= 1
|
self._level -= 1
|
||||||
|
|
||||||
tu_processed_headers.update([
|
tu_processed_headers.update(
|
||||||
os.path.abspath(str(hdr.source))
|
[os.path.abspath(str(hdr.source)) for hdr in translation_unit.get_includes()])
|
||||||
for hdr in translation_unit.get_includes()
|
|
||||||
])
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
@@ -857,8 +834,7 @@ def get_filter_funcs(verilator_root: str):
|
|||||||
filename = os.path.abspath(node.location.file.name)
|
filename = os.path.abspath(node.location.file.name)
|
||||||
return not filename.startswith(verilator_root)
|
return not filename.startswith(verilator_root)
|
||||||
|
|
||||||
def is_ignored_def(node: clang.cindex.Cursor,
|
def is_ignored_def(node: clang.cindex.Cursor, refd: clang.cindex.Cursor) -> bool:
|
||||||
refd: clang.cindex.Cursor) -> bool:
|
|
||||||
# __*
|
# __*
|
||||||
if str(refd.spelling).startswith("__"):
|
if str(refd.spelling).startswith("__"):
|
||||||
return True
|
return True
|
||||||
@@ -901,8 +877,7 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
|||||||
os.chdir(compile_command.directory)
|
os.chdir(compile_command.directory)
|
||||||
|
|
||||||
index = Index.create()
|
index = Index.create()
|
||||||
translation_unit = index.parse(compile_command.filename,
|
translation_unit = index.parse(compile_command.filename, compile_command.args)
|
||||||
compile_command.args)
|
|
||||||
for diag in translation_unit.diagnostics:
|
for diag in translation_unit.diagnostics:
|
||||||
if diag.severity >= clang.cindex.Diagnostic.Error:
|
if diag.severity >= clang.cindex.Diagnostic.Error:
|
||||||
errors.append(str(diag))
|
errors.append(str(diag))
|
||||||
@@ -910,23 +885,20 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
|||||||
if len(errors) == 0:
|
if len(errors) == 0:
|
||||||
pch_file = os.path.join(
|
pch_file = os.path.join(
|
||||||
tmp_dir,
|
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)
|
translation_unit.save(pch_file)
|
||||||
|
|
||||||
if pch_file:
|
if pch_file:
|
||||||
return pch_file
|
return pch_file
|
||||||
|
|
||||||
except (TranslationUnitSaveError, TranslationUnitLoadError,
|
except (TranslationUnitSaveError, TranslationUnitLoadError, OSError) as exception:
|
||||||
OSError) as exception:
|
|
||||||
print(f"%Warning: {exception}", file=sys.stderr)
|
print(f"%Warning: {exception}", file=sys.stderr)
|
||||||
|
|
||||||
finally:
|
finally:
|
||||||
os.chdir(initial_cwd)
|
os.chdir(initial_cwd)
|
||||||
|
|
||||||
print(
|
print(f"%Warning: Precompilation failed, skipping: {compile_command.filename}",
|
||||||
f"%Warning: Precompilation failed, skipping: {compile_command.filename}",
|
file=sys.stderr)
|
||||||
file=sys.stderr)
|
|
||||||
for error in errors:
|
for error in errors:
|
||||||
print(f" {error}", file=sys.stderr)
|
print(f" {error}", file=sys.stderr)
|
||||||
return ""
|
return ""
|
||||||
@@ -934,10 +906,8 @@ def precompile_header(compile_command: CompileCommand, tmp_dir: str) -> str:
|
|||||||
|
|
||||||
# Compile and analyze inputs in a single process.
|
# Compile and analyze inputs in a single process.
|
||||||
def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
||||||
diagnostic_cb: Callable[[Diagnostic],
|
diagnostic_cb: Callable[[Diagnostic], None], verilator_root: str):
|
||||||
None], verilator_root: 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)
|
|
||||||
|
|
||||||
prefix = "verilator_clang_check_attributes_"
|
prefix = "verilator_clang_check_attributes_"
|
||||||
with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir:
|
with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir:
|
||||||
@@ -947,8 +917,8 @@ def run_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
|||||||
if pch_file:
|
if pch_file:
|
||||||
extra_args += ["-include-pch", pch_file]
|
extra_args += ["-include-pch", pch_file]
|
||||||
|
|
||||||
cav = CallAnnotationsValidator(diagnostic_cb, is_ignored_top_level,
|
cav = CallAnnotationsValidator(diagnostic_cb, is_ignored_top_level, is_ignored_def,
|
||||||
is_ignored_def, is_ignored_call)
|
is_ignored_call)
|
||||||
for compile_command in ccl:
|
for compile_command in ccl:
|
||||||
cav.compile_and_analyze_file(compile_command.filename,
|
cav.compile_and_analyze_file(compile_command.filename,
|
||||||
extra_args + compile_command.args,
|
extra_args + compile_command.args,
|
||||||
@@ -963,12 +933,11 @@ class ParallelAnalysisProcess:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def init_data(verilator_root: str, tmp_dir: str):
|
def init_data(verilator_root: str, tmp_dir: str):
|
||||||
(is_ignored_top_level, is_ignored_def,
|
(is_ignored_top_level, is_ignored_def, is_ignored_call) = get_filter_funcs(verilator_root)
|
||||||
is_ignored_call) = get_filter_funcs(verilator_root)
|
|
||||||
|
|
||||||
ParallelAnalysisProcess.cav = CallAnnotationsValidator(
|
ParallelAnalysisProcess.cav = CallAnnotationsValidator(
|
||||||
ParallelAnalysisProcess._diagnostic_handler, is_ignored_top_level,
|
ParallelAnalysisProcess._diagnostic_handler, is_ignored_top_level, is_ignored_def,
|
||||||
is_ignored_def, is_ignored_call)
|
is_ignored_call)
|
||||||
ParallelAnalysisProcess.tmp_dir = tmp_dir
|
ParallelAnalysisProcess.tmp_dir = tmp_dir
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -979,31 +948,27 @@ class ParallelAnalysisProcess:
|
|||||||
def analyze_cpp_file(compile_command: CompileCommand) -> set[Diagnostic]:
|
def analyze_cpp_file(compile_command: CompileCommand) -> set[Diagnostic]:
|
||||||
ParallelAnalysisProcess.diags = set()
|
ParallelAnalysisProcess.diags = set()
|
||||||
assert ParallelAnalysisProcess.cav is not None
|
assert ParallelAnalysisProcess.cav is not None
|
||||||
ParallelAnalysisProcess.cav.compile_and_analyze_file(
|
ParallelAnalysisProcess.cav.compile_and_analyze_file(compile_command.filename,
|
||||||
compile_command.filename, compile_command.args,
|
compile_command.args,
|
||||||
compile_command.directory)
|
compile_command.directory)
|
||||||
return ParallelAnalysisProcess.diags
|
return ParallelAnalysisProcess.diags
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def precompile_header(compile_command: CompileCommand) -> str:
|
def precompile_header(compile_command: CompileCommand) -> str:
|
||||||
return precompile_header(compile_command,
|
return precompile_header(compile_command, ParallelAnalysisProcess.tmp_dir)
|
||||||
ParallelAnalysisProcess.tmp_dir)
|
|
||||||
|
|
||||||
|
|
||||||
# Compile and analyze inputs in multiple processes.
|
# Compile and analyze inputs in multiple processes.
|
||||||
def run_parallel_analysis(ccl: Iterable[CompileCommand],
|
def run_parallel_analysis(ccl: Iterable[CompileCommand], pccl: Iterable[CompileCommand],
|
||||||
pccl: Iterable[CompileCommand],
|
diagnostic_cb: Callable[[Diagnostic],
|
||||||
diagnostic_cb: Callable[[Diagnostic], None],
|
None], jobs_count: int, verilator_root: str):
|
||||||
jobs_count: int, verilator_root: str):
|
|
||||||
prefix = "verilator_clang_check_attributes_"
|
prefix = "verilator_clang_check_attributes_"
|
||||||
with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir:
|
with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir:
|
||||||
with multiprocessing.Pool(
|
with multiprocessing.Pool(processes=jobs_count,
|
||||||
processes=jobs_count,
|
initializer=ParallelAnalysisProcess.init_data,
|
||||||
initializer=ParallelAnalysisProcess.init_data,
|
initargs=[verilator_root, tmp_dir]) as pool:
|
||||||
initargs=[verilator_root, tmp_dir]) as pool:
|
|
||||||
extra_args = []
|
extra_args = []
|
||||||
for pch_file in pool.imap_unordered(
|
for pch_file in pool.imap_unordered(ParallelAnalysisProcess.precompile_header, pccl):
|
||||||
ParallelAnalysisProcess.precompile_header, pccl):
|
|
||||||
if pch_file:
|
if pch_file:
|
||||||
extra_args += ["-include-pch", pch_file]
|
extra_args += ["-include-pch", pch_file]
|
||||||
|
|
||||||
@@ -1011,8 +976,7 @@ def run_parallel_analysis(ccl: Iterable[CompileCommand],
|
|||||||
for compile_command in ccl:
|
for compile_command in ccl:
|
||||||
compile_command.args = compile_command.args + extra_args
|
compile_command.args = compile_command.args + extra_args
|
||||||
|
|
||||||
for diags in pool.imap_unordered(
|
for diags in pool.imap_unordered(ParallelAnalysisProcess.analyze_cpp_file, ccl, 1):
|
||||||
ParallelAnalysisProcess.analyze_cpp_file, ccl, 1):
|
|
||||||
for diag in diags:
|
for diag in diags:
|
||||||
diagnostic_cb(diag)
|
diagnostic_cb(diag)
|
||||||
|
|
||||||
@@ -1057,8 +1021,7 @@ class TopDownSummaryPrinter():
|
|||||||
row_groups: dict[str, list[list[str]]] = {}
|
row_groups: dict[str, list[list[str]]] = {}
|
||||||
column_widths = [0, 0]
|
column_widths = [0, 0]
|
||||||
for func in sorted(self._funcs.values(),
|
for func in sorted(self._funcs.values(),
|
||||||
key=lambda func:
|
key=lambda func: (func.info.file, func.info.line, func.info.usr)):
|
||||||
(func.info.file, func.info.line, func.info.usr)):
|
|
||||||
func_info = func.info
|
func_info = func.info
|
||||||
relfile = os.path.relpath(func_info.file, root_dir)
|
relfile = os.path.relpath(func_info.file, root_dir)
|
||||||
|
|
||||||
@@ -1082,31 +1045,23 @@ class TopDownSummaryPrinter():
|
|||||||
if func.mismatch:
|
if func.mismatch:
|
||||||
mrelfile = os.path.relpath(func.mismatch.file, root_dir)
|
mrelfile = os.path.relpath(func.mismatch.file, root_dir)
|
||||||
row_group.append([
|
row_group.append([
|
||||||
f"{mrelfile}:{func.mismatch.line}:",
|
f"{mrelfile}:{func.mismatch.line}:", f"[{func.mismatch.annotations}]",
|
||||||
f"[{func.mismatch.annotations}]",
|
|
||||||
func.mismatch.name + " [declaration]"
|
func.mismatch.name + " [declaration]"
|
||||||
])
|
])
|
||||||
|
|
||||||
row_group.append([
|
row_group.append(
|
||||||
f"{relfile}:{func_info.line}:", f"[{func_info.annotations}]",
|
[f"{relfile}:{func_info.line}:", f"[{func_info.annotations}]", func_info.name])
|
||||||
func_info.name
|
|
||||||
])
|
|
||||||
|
|
||||||
for callee in sorted(func.calees,
|
for callee in sorted(func.calees, key=lambda func: (func.file, func.line, func.usr)):
|
||||||
key=lambda func:
|
|
||||||
(func.file, func.line, func.usr)):
|
|
||||||
crelfile = os.path.relpath(callee.file, root_dir)
|
crelfile = os.path.relpath(callee.file, root_dir)
|
||||||
row_group.append([
|
row_group.append(
|
||||||
f"{crelfile}:{callee.line}:", f"[{callee.annotations}]",
|
[f"{crelfile}:{callee.line}:", f"[{callee.annotations}]", " " + callee.name])
|
||||||
" " + callee.name
|
|
||||||
])
|
|
||||||
|
|
||||||
row_groups[name] = row_group
|
row_groups[name] = row_group
|
||||||
|
|
||||||
for row in row_group:
|
for row in row_group:
|
||||||
for row_id, value in enumerate(row[0:-1]):
|
for row_id, value in enumerate(row[0:-1]):
|
||||||
column_widths[row_id] = max(column_widths[row_id],
|
column_widths[row_id] = max(column_widths[row_id], len(value))
|
||||||
len(value))
|
|
||||||
|
|
||||||
for label, rows in sorted(row_groups.items(), key=lambda kv: kv[0]):
|
for label, rows in sorted(row_groups.items(), key=lambda kv: kv[0]):
|
||||||
self.begin_group(label)
|
self.begin_group(label)
|
||||||
@@ -1114,21 +1069,17 @@ class TopDownSummaryPrinter():
|
|||||||
print(f"{row[0]:<{column_widths[0]}} "
|
print(f"{row[0]:<{column_widths[0]}} "
|
||||||
f"{row[1]:<{column_widths[1]}} "
|
f"{row[1]:<{column_widths[1]}} "
|
||||||
f"{row[2]}")
|
f"{row[2]}")
|
||||||
print(
|
print(f"Number of functions reported unsafe: {len(self._unsafe_in_safe)}")
|
||||||
f"Number of functions reported unsafe: {len(self._unsafe_in_safe)}"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
default_verilator_root = os.path.abspath(
|
default_verilator_root = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
|
||||||
os.path.join(os.path.dirname(__file__), ".."))
|
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description="""Check function annotations for correctness""",
|
description="""Check function annotations for correctness""",
|
||||||
epilog=
|
epilog="""Copyright 2022-2024 by Wilson Snyder. Verilator is free software;
|
||||||
"""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
|
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.
|
Lesser General Public License Version 3 or the Apache License 2.0.
|
||||||
SPDX-License-Identifier: LGPL-3.0-only OR Apache-2.0""")
|
SPDX-License-Identifier: LGPL-3.0-only OR Apache-2.0""")
|
||||||
@@ -1142,29 +1093,23 @@ def main():
|
|||||||
type=int,
|
type=int,
|
||||||
default=0,
|
default=0,
|
||||||
help="Number of parallel jobs to use.")
|
help="Number of parallel jobs to use.")
|
||||||
parser.add_argument(
|
parser.add_argument("--compile-commands-dir",
|
||||||
"--compile-commands-dir",
|
type=str,
|
||||||
type=str,
|
default=None,
|
||||||
default=None,
|
help="Path to directory containing compile_commands.json.")
|
||||||
help="Path to directory containing compile_commands.json.")
|
|
||||||
parser.add_argument("--cxxflags",
|
parser.add_argument("--cxxflags",
|
||||||
type=str,
|
type=str,
|
||||||
default=None,
|
default=None,
|
||||||
help="Extra flags passed to clang++.")
|
help="Extra flags passed to clang++.")
|
||||||
parser.add_argument(
|
parser.add_argument("--compilation-root",
|
||||||
"--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",
|
|
||||||
type=str,
|
type=str,
|
||||||
nargs="+",
|
default=os.getcwd(),
|
||||||
help="Source file to analyze.")
|
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()
|
cmdline = parser.parse_args()
|
||||||
|
|
||||||
@@ -1179,8 +1124,7 @@ def main():
|
|||||||
|
|
||||||
compdb: Optional[CompilationDatabase] = None
|
compdb: Optional[CompilationDatabase] = None
|
||||||
if cmdline.compile_commands_dir:
|
if cmdline.compile_commands_dir:
|
||||||
compdb = CompilationDatabase.fromDirectory(
|
compdb = CompilationDatabase.fromDirectory(cmdline.compile_commands_dir)
|
||||||
cmdline.compile_commands_dir)
|
|
||||||
|
|
||||||
if cmdline.cxxflags is not None:
|
if cmdline.cxxflags is not None:
|
||||||
common_cxxflags = shlex.split(cmdline.cxxflags)
|
common_cxxflags = shlex.split(cmdline.cxxflags)
|
||||||
@@ -1230,8 +1174,7 @@ def main():
|
|||||||
summary_printer.handle_diagnostic, verilator_root)
|
summary_printer.handle_diagnostic, verilator_root)
|
||||||
else:
|
else:
|
||||||
run_parallel_analysis(compile_commands_list, precompile_commands_list,
|
run_parallel_analysis(compile_commands_list, precompile_commands_list,
|
||||||
summary_printer.handle_diagnostic, cmdline.jobs,
|
summary_printer.handle_diagnostic, cmdline.jobs, verilator_root)
|
||||||
verilator_root)
|
|
||||||
|
|
||||||
summary_printer.print_summary(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):
|
if not Args.scenarios or re.match('dist', Args.scenarios):
|
||||||
run("make examples VERILATOR_NO_OPT_BUILD=1")
|
run("make examples VERILATOR_NO_OPT_BUILD=1")
|
||||||
run("make test_regress VERILATOR_NO_OPT_BUILD=1" +
|
run("make test_regress VERILATOR_NO_OPT_BUILD=1" +
|
||||||
(" SCENARIOS='" + Args.scenarios +
|
(" SCENARIOS='" + Args.scenarios + "'" if Args.scenarios else "") +
|
||||||
"'" if Args.scenarios else "") +
|
(" DRIVER_HASHSET='--hashset=" + Args.hashset + "'" if Args.hashset else "") +
|
||||||
(" DRIVER_HASHSET='--hashset=" + Args.hashset +
|
|
||||||
"'" if Args.hashset else "") +
|
|
||||||
('' if Args.stop else ' || true'))
|
('' if Args.stop else ' || true'))
|
||||||
else:
|
else:
|
||||||
for test in Args.tests:
|
for test in Args.tests:
|
||||||
if not os.path.exists(test) and os.path.exists(
|
if not os.path.exists(test) and os.path.exists("test_regress/t/" + test):
|
||||||
"test_regress/t/" + test):
|
|
||||||
test = "test_regress/t/" + test
|
test = "test_regress/t/" + test
|
||||||
run(test)
|
run(test)
|
||||||
ci_fold_end()
|
ci_fold_end()
|
||||||
@@ -78,8 +75,7 @@ def test():
|
|||||||
os.makedirs(cc_dir, exist_ok=True)
|
os.makedirs(cc_dir, exist_ok=True)
|
||||||
os.makedirs(cc_dir + "/info", exist_ok=True)
|
os.makedirs(cc_dir + "/info", exist_ok=True)
|
||||||
|
|
||||||
with subprocess.Popen("find . -print | grep .gcda",
|
with subprocess.Popen("find . -print | grep .gcda", shell=True,
|
||||||
shell=True,
|
|
||||||
stdout=subprocess.PIPE) as sp:
|
stdout=subprocess.PIPE) as sp:
|
||||||
datout = sp.stdout.read()
|
datout = sp.stdout.read()
|
||||||
|
|
||||||
@@ -98,8 +94,7 @@ def test():
|
|||||||
del dats[dat]
|
del dats[dat]
|
||||||
break
|
break
|
||||||
|
|
||||||
with subprocess.Popen("find . -print | grep .gcno",
|
with subprocess.Popen("find . -print | grep .gcno", shell=True,
|
||||||
shell=True,
|
|
||||||
stdout=subprocess.PIPE) as sp:
|
stdout=subprocess.PIPE) as sp:
|
||||||
datout = sp.stdout.read()
|
datout = sp.stdout.read()
|
||||||
|
|
||||||
@@ -116,8 +111,7 @@ def test():
|
|||||||
if gbase in gcnos:
|
if gbase in gcnos:
|
||||||
os.symlink(gcnos[gbase], gcno)
|
os.symlink(gcnos[gbase], gcno)
|
||||||
else:
|
else:
|
||||||
print("MISSING .gcno for a .gcda: " + gcno,
|
print("MISSING .gcno for a .gcda: " + gcno, file=sys.stderr)
|
||||||
file=sys.stderr)
|
|
||||||
ci_fold_end()
|
ci_fold_end()
|
||||||
|
|
||||||
if Args.stage_enabled[5]:
|
if Args.stage_enabled[5]:
|
||||||
@@ -142,8 +136,7 @@ def test():
|
|||||||
if Args.stage_enabled[11]:
|
if Args.stage_enabled[11]:
|
||||||
ci_fold_start("dirs")
|
ci_fold_start("dirs")
|
||||||
print("Stage 11: Cleanup paths")
|
print("Stage 11: Cleanup paths")
|
||||||
cleanup_abs_paths_info(cc_dir, cc_dir + "/app_total.info",
|
cleanup_abs_paths_info(cc_dir, cc_dir + "/app_total.info", cc_dir + "/app_total.info")
|
||||||
cc_dir + "/app_total.info")
|
|
||||||
ci_fold_end()
|
ci_fold_end()
|
||||||
|
|
||||||
if Args.stage_enabled[12]:
|
if Args.stage_enabled[12]:
|
||||||
@@ -164,34 +157,38 @@ def test():
|
|||||||
inc = "--include " + inc
|
inc = "--include " + inc
|
||||||
if exc != '':
|
if exc != '':
|
||||||
exc = "--exclude " + exc
|
exc = "--exclude " + exc
|
||||||
run("cd " + cc_dir + " ; " + RealPath +
|
run("cd " + cc_dir + " ; " + RealPath + "/fastcov.py -C app_total.info " + inc + " " +
|
||||||
"/fastcov.py -C app_total.info " + inc + " " + exc +
|
exc + " -x --lcov -o app_total_f.info")
|
||||||
" -x --lcov -o app_total_f.info")
|
|
||||||
ci_fold_end()
|
ci_fold_end()
|
||||||
|
|
||||||
if Args.stage_enabled[17]:
|
if Args.stage_enabled[17]:
|
||||||
ci_fold_start("report")
|
ci_fold_start("report")
|
||||||
print("Stage 17: Create HTML")
|
print("Stage 17: Create HTML")
|
||||||
run("cd " + cc_dir + " ; genhtml app_total_f.info --demangle-cpp" +
|
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()
|
ci_fold_end()
|
||||||
|
|
||||||
if Args.stage_enabled[18]:
|
if Args.stage_enabled[18]:
|
||||||
ci_fold_start("upload")
|
ci_fold_start("upload")
|
||||||
print("Stage 18: Upload")
|
print("Stage 18: Upload")
|
||||||
cmd = "bash <(cat ci/coverage-upload.sh) -f " + cc_dir + "/app_total.info"
|
# curl -Os https://cli.codecov.io/latest/linux/codecov ; sudo chmod +x codecov
|
||||||
print("print: Not running: export CODECOV_TOKEN=<hidden>")
|
# --disable-search does not seem to work
|
||||||
print("print: Not running: " + cmd)
|
# -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()
|
ci_fold_end()
|
||||||
|
|
||||||
if Args.stage_enabled[19]:
|
if Args.stage_enabled[19]:
|
||||||
print("*-* All Finished *-*")
|
print("*-* All Finished *-*")
|
||||||
print("")
|
print("")
|
||||||
print("* See report in " + cc_dir + "/html/index.html")
|
print("* See report in " + cc_dir + "/html/index.html")
|
||||||
print(
|
print("* Remember to make distclean && ./configure before working on non-coverage")
|
||||||
"* Remember to make distclean && ./configure before working on non-coverage"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def clone_sources(cc_dir):
|
def clone_sources(cc_dir):
|
||||||
@@ -200,9 +197,8 @@ def clone_sources(cc_dir):
|
|||||||
for globf in Source_Globs:
|
for globf in Source_Globs:
|
||||||
for infile in glob.glob(globf):
|
for infile in glob.glob(globf):
|
||||||
if re.match(r'^/', infile):
|
if re.match(r'^/', infile):
|
||||||
sys.exit(
|
sys.exit("%Error: source globs should be relative not absolute filenames, " +
|
||||||
"%Error: source globs should be relative not absolute filenames, "
|
infile)
|
||||||
+ infile)
|
|
||||||
outfile = cc_dir + "/" + infile
|
outfile = cc_dir + "/" + infile
|
||||||
outpath = re.sub(r'/[^/]*$', '', outfile, count=1)
|
outpath = re.sub(r'/[^/]*$', '', outfile, count=1)
|
||||||
os.makedirs(outpath, exist_ok=True)
|
os.makedirs(outpath, exist_ok=True)
|
||||||
@@ -243,22 +239,20 @@ def clone_sources(cc_dir):
|
|||||||
done = True
|
done = True
|
||||||
|
|
||||||
ofh.write(line + "\n")
|
ofh.write(line + "\n")
|
||||||
print("Number of source lines automatically LCOV_EXCL_LINE'ed: %d" %
|
print("Number of source lines automatically LCOV_EXCL_LINE'ed: %d" % excluded_lines)
|
||||||
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_BR_LINE'ed: %d" %
|
|
||||||
excluded_br_lines)
|
|
||||||
|
|
||||||
|
|
||||||
def cleanup_abs_paths_info(cc_dir, infile, outfile):
|
def cleanup_abs_paths_info(cc_dir, infile, outfile):
|
||||||
lines = []
|
lines = []
|
||||||
with open(infile, "r", encoding="utf8") as fh:
|
with open(infile, "r", encoding="utf8") as fh:
|
||||||
for line in fh:
|
for line in fh:
|
||||||
if re.search(r'^SF:', line):
|
if re.search(r'^SF:', line) and not re.search(r'^SF:/usr/', line):
|
||||||
line = re.sub(os.environ['VERILATOR_ROOT'] + '/',
|
line = re.sub(os.environ['VERILATOR_ROOT'] + '/', '', line, count=1)
|
||||||
'',
|
|
||||||
line,
|
|
||||||
count=1)
|
|
||||||
line = re.sub(cc_dir + '/', '', 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)
|
line = re.sub(r'obj_dbg/verilog.y$', 'verilog.y', line)
|
||||||
# print("Remaining SF: "+line)
|
# print("Remaining SF: "+line)
|
||||||
lines.append(line)
|
lines.append(line)
|
||||||
@@ -340,15 +334,13 @@ def ci_fold_end():
|
|||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description=
|
description="""code_coverage builds Verilator with C++ coverage support and runs
|
||||||
"""code_coverage builds Verilator with C++ coverage support and runs
|
|
||||||
tests with coverage enabled. This will rebuild the current object
|
tests with coverage enabled. This will rebuild the current object
|
||||||
files. Run as:
|
files. Run as:
|
||||||
|
|
||||||
cd $VERILATOR_ROOT
|
cd $VERILATOR_ROOT
|
||||||
nodist/code_coverage""",
|
nodist/code_coverage""",
|
||||||
epilog=
|
epilog="""Copyright 2019-2024 by Wilson Snyder. This program is free software; you
|
||||||
"""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
|
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
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
Version 2.0.
|
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('--debug', action='store_true', help='enable debug')
|
||||||
parser.add_argument('--hashset',
|
parser.add_argument('--hashset',
|
||||||
action='store',
|
action='store',
|
||||||
help='pass test hashset onto driver.pl test harness')
|
help='pass test hashset onto driver.py test harness')
|
||||||
parser.add_argument('--scenarios',
|
parser.add_argument('--scenarios',
|
||||||
action='store',
|
action='store',
|
||||||
help='pass test scenarios onto driver.pl test harness')
|
help='pass test scenarios onto driver.py test harness')
|
||||||
parser.add_argument(
|
parser.add_argument('--stages',
|
||||||
'--stages',
|
'--stage',
|
||||||
action='store',
|
action='store',
|
||||||
help='runs a specific stage or range of stages (see the script)')
|
help='runs a specific stage or range of stages (see the script)')
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
|
'--tests',
|
||||||
'--test',
|
'--test',
|
||||||
action='append',
|
action='append',
|
||||||
dest='tests',
|
|
||||||
default=[],
|
default=[],
|
||||||
help=
|
help='Instead of normal regressions, run the specified test(s), may be used multiple times')
|
||||||
'Instead of normal regressions, run the specified test(s), may be used multiple times'
|
|
||||||
)
|
|
||||||
parser.add_argument('--no-stop',
|
parser.add_argument('--no-stop',
|
||||||
dest='stop',
|
dest='stop',
|
||||||
action='store_false',
|
action='store_false',
|
||||||
|
|||||||
+10
-21
@@ -20,8 +20,7 @@ def dotread(filename):
|
|||||||
vnum = 0
|
vnum = 0
|
||||||
|
|
||||||
vertex_re = re.compile(r'^\t([a-zA-Z0-9_]+)\t(.*)$')
|
vertex_re = re.compile(r'^\t([a-zA-Z0-9_]+)\t(.*)$')
|
||||||
edge_re = re.compile(
|
edge_re = re.compile(r'^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s*(.*)$')
|
||||||
r'^\t([a-zA-Z0-9_]+)\s+->\s+([a-zA-Z0-9_]+)\s*(.*)$')
|
|
||||||
|
|
||||||
for line in fh:
|
for line in fh:
|
||||||
vertex_match = re.search(vertex_re, line)
|
vertex_match = re.search(vertex_re, line)
|
||||||
@@ -29,11 +28,7 @@ def dotread(filename):
|
|||||||
if vertex_match:
|
if vertex_match:
|
||||||
if vertex_match.group(1) != 'nTITLE':
|
if vertex_match.group(1) != 'nTITLE':
|
||||||
header = False
|
header = False
|
||||||
Vertexes.append({
|
Vertexes.append({'num': vnum, 'line': line, 'name': vertex_match.group(1)})
|
||||||
'num': vnum,
|
|
||||||
'line': line,
|
|
||||||
'name': vertex_match.group(1)
|
|
||||||
})
|
|
||||||
vnum += 1
|
vnum += 1
|
||||||
elif edge_match:
|
elif edge_match:
|
||||||
fromv = edge_match.group(1)
|
fromv = edge_match.group(1)
|
||||||
@@ -65,14 +60,13 @@ def cwrite(filename):
|
|||||||
fh.write("void V3GraphTestImport::dotImport() {\n")
|
fh.write("void V3GraphTestImport::dotImport() {\n")
|
||||||
fh.write(" auto* gp = &m_graph;\n")
|
fh.write(" auto* gp = &m_graph;\n")
|
||||||
for ver in sorted(Vertexes, key=lambda ver: ver['num']):
|
for ver in sorted(Vertexes, key=lambda ver: ver['num']):
|
||||||
fh.write(
|
fh.write(" auto* %s = new V3GraphTestVertex{gp, \"%s\"}; if (%s) {}\n" %
|
||||||
" auto* %s = new V3GraphTestVertex{gp, \"%s\"}; if (%s) {}\n"
|
(ver['name'], ver['name'], ver['name']))
|
||||||
% (ver['name'], ver['name'], ver['name']))
|
|
||||||
fh.write("\n")
|
fh.write("\n")
|
||||||
for edge in Edges:
|
for edge in Edges:
|
||||||
fh.write(" new V3GraphEdge{gp, %s, %s, %s, %s};\n" %
|
fh.write(
|
||||||
(edge['from'], edge['to'], edge['weight'],
|
" new V3GraphEdge{gp, %s, %s, %s, %s};\n" %
|
||||||
"true" if edge['cutable'] else "false"))
|
(edge['from'], edge['to'], edge['weight'], "true" if edge['cutable'] else "false"))
|
||||||
fh.write("}\n")
|
fh.write("}\n")
|
||||||
|
|
||||||
|
|
||||||
@@ -82,22 +76,17 @@ def cwrite(filename):
|
|||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description=
|
description="""dot_importer takes a graphvis .dot file and converts into .cpp file.
|
||||||
"""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
|
This x.cpp file is then manually included in V3GraphTest.cpp to verify
|
||||||
various xsub-algorithms.""",
|
various xsub-algorithms.""",
|
||||||
epilog=
|
epilog="""Copyright 2005-2024 by Wilson Snyder. This program is free software; you
|
||||||
"""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
|
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
|
Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
Version 2.0.
|
Version 2.0.
|
||||||
|
|
||||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0""")
|
||||||
|
|
||||||
parser.add_argument('--debug',
|
parser.add_argument('--debug', action='store_const', const=9, help='enable debug')
|
||||||
action='store_const',
|
|
||||||
const=9,
|
|
||||||
help='enable debug')
|
|
||||||
parser.add_argument('filename', help='input .dot filename to process')
|
parser.add_argument('filename', help='input .dot filename to process')
|
||||||
|
|
||||||
Args = parser.parse_args()
|
Args = parser.parse_args()
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user