mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cefccf5d2 | ||
|
|
925fb921a2 | ||
|
|
fcd1306ef3 | ||
|
|
9d2f1c607a | ||
|
|
f331c192b4 | ||
|
|
d192372c7e | ||
|
|
7b073fec7d | ||
|
|
424faa883e | ||
|
|
61d6546400 | ||
|
|
972a11537c | ||
|
|
609bfa46e8 | ||
|
|
01b521a0ea | ||
|
|
0a3c90e517 | ||
|
|
afc66f6a85 | ||
|
|
722e38f532 | ||
|
|
86b07423a9 | ||
|
|
3f4d4dec77 | ||
|
|
86e3c02339 | ||
|
|
b6cdae30f6 | ||
|
|
a9ff0a0f32 | ||
|
|
a0e7930036 | ||
|
|
d61ad04f32 | ||
|
|
0824ef377f | ||
|
|
fc2654f1f6 | ||
|
|
5aa935d170 | ||
|
|
bcf58defe0 | ||
|
|
2dc0053ea4 | ||
|
|
4b6e15d0eb | ||
|
|
87bb32fde1 | ||
|
|
ea1b141d13 | ||
|
|
84c7368621 | ||
|
|
675cc891a5 | ||
|
|
0809c17ce1 | ||
|
|
f27cf4c804 | ||
|
|
701d2277cd | ||
|
|
338e875b70 | ||
|
|
87135d0b2d | ||
|
|
e465a30eee | ||
|
|
889a1211f1 | ||
|
|
31d8b4cb8e | ||
|
|
d87ef8394a | ||
|
|
4f4c26383c | ||
|
|
42e4e18ec8 | ||
|
|
355c4f76d0 | ||
|
|
073dc03adc | ||
|
|
468a33b61c | ||
|
|
8ff607f679 | ||
|
|
6143892619 | ||
|
|
b51bb4d0e7 | ||
|
|
f0a7abcef8 | ||
|
|
faedcc755b | ||
|
|
ff9596bb23 | ||
|
|
7d807a7e0e | ||
|
|
e569ff2752 | ||
|
|
68e1b473e2 | ||
|
|
4452a9b10f | ||
|
|
6349e76abd | ||
|
|
f4be3d5d2b | ||
|
|
054b792021 | ||
|
|
c303ba7f0a | ||
|
|
2c7f1ef40f | ||
|
|
5f583b0680 | ||
|
|
fa4270b551 | ||
|
|
d8071819fc | ||
|
|
833780fac1 | ||
|
|
4b3731d318 | ||
|
|
68f8617f79 | ||
|
|
a83ed6b06f | ||
|
|
821dd070bf | ||
|
|
06fdf7be58 | ||
|
|
e97e6c2213 | ||
|
|
508e937164 | ||
|
|
57975c82b7 | ||
|
|
66d85b3381 | ||
|
|
73d6de4471 | ||
|
|
0af02563ca | ||
|
|
b82ce5743b | ||
|
|
d3c1f4353e | ||
|
|
62bdd3ab49 | ||
|
|
2eed4452ad | ||
|
|
f44cd9cd48 | ||
|
|
25f970eac2 | ||
|
|
3abb65d732 | ||
|
|
352d0b4582 | ||
|
|
a60e273c29 | ||
|
|
47253450a4 | ||
|
|
278d532368 | ||
|
|
6297650fef | ||
|
|
5634e96bb6 | ||
|
|
e266b2cb03 | ||
|
|
0af3efda5c | ||
|
|
d3e1c40238 | ||
|
|
aacb38b776 | ||
|
|
21d80cdfa1 | ||
|
|
d0e7177d8e | ||
|
|
cd2208ea3f | ||
|
|
3a27e3d67b | ||
|
|
09dff9c3a7 | ||
|
|
f266b02bc7 | ||
|
|
de9c92fd14 | ||
|
|
0322e9da7e | ||
|
|
b2d92b7c25 | ||
|
|
ef72b73a59 | ||
|
|
749aab0a56 | ||
|
|
cd8528e83b | ||
|
|
e8a1e4745c | ||
|
|
96306b7630 | ||
|
|
d41efb189d | ||
|
|
3c77c7bb92 | ||
|
|
3ddfa214e3 | ||
|
|
a58cd66358 | ||
|
|
79e0fa3327 | ||
|
|
f782496092 | ||
|
|
dc28e7f3e2 | ||
|
|
e6da59eecd | ||
|
|
04f68cbd99 | ||
|
|
8c6d1e53ca | ||
|
|
c6ecd60993 | ||
|
|
ee26dddfa1 | ||
|
|
d1658b9e82 | ||
|
|
818347f99b | ||
|
|
201419c646 | ||
|
|
d25834e57b | ||
|
|
4f50073feb | ||
|
|
218dd4322b | ||
|
|
eaf09ba0e7 | ||
|
|
8291d8bcc1 | ||
|
|
0a045a7bf6 | ||
|
|
dbcaad99c5 | ||
|
|
6736e92cdb | ||
|
|
a427860825 | ||
|
|
41d2ebe288 | ||
|
|
227e61f891 | ||
|
|
b2e61425d6 | ||
|
|
9d7c4d9af3 | ||
|
|
0c75d4eaca | ||
|
|
528a73a492 | ||
|
|
fbf2e59c85 | ||
|
|
16586d1d37 | ||
|
|
441b5da5ce | ||
|
|
207bc2b18a | ||
|
|
e64295e92b | ||
|
|
cbf9cc8e5f | ||
|
|
a29d9469da | ||
|
|
2a3eabff73 | ||
|
|
454efbe3fc | ||
|
|
fb9ec03c3f | ||
|
|
21926eeb6b | ||
|
|
6ae6b16223 | ||
|
|
167f4ebbd4 | ||
|
|
d6126c4b32 | ||
|
|
8d61cea366 | ||
|
|
65e08f4dbf | ||
|
|
cf4c00e3b4 | ||
|
|
bac98df46b | ||
|
|
0b0b642241 | ||
|
|
52d29d238c | ||
|
|
0675510eb9 | ||
|
|
99791ac8b3 | ||
|
|
ee26378394 | ||
|
|
54c4351c39 | ||
|
|
e504e9aced | ||
|
|
ef2776034e | ||
|
|
5c658f8cd5 | ||
|
|
0ed7aaeabd | ||
|
|
5f9b0929b4 | ||
|
|
65290afe0a | ||
|
|
ed93a111c2 | ||
|
|
3487701b04 | ||
|
|
d33a3d09f7 | ||
|
|
0716a28816 | ||
|
|
8e1901da10 | ||
|
|
ecfa385f13 | ||
|
|
63df87e220 | ||
|
|
495d52d30f | ||
|
|
2df886b2b0 | ||
|
|
fcf0d03cd4 | ||
|
|
4154584c4b | ||
|
|
a57a3579c0 | ||
|
|
203993b018 | ||
|
|
347e9b4ec8 | ||
|
|
9d02082801 | ||
|
|
785c51dd0b | ||
|
|
2e4f5c863f | ||
|
|
196f3292d5 | ||
|
|
627a144b83 | ||
|
|
5688d1a935 | ||
|
|
8b0d71994d | ||
|
|
79682e6072 | ||
|
|
7e1b92fa75 | ||
|
|
ca8ef7ce73 | ||
|
|
23d538fdaf | ||
|
|
aaadc3def7 | ||
|
|
444a4a760c | ||
|
|
b42799f3b5 | ||
|
|
7b07cf912e | ||
|
|
6a3ec17887 | ||
|
|
8c3ca30c91 | ||
|
|
0e4da3b0bf | ||
|
|
e6add5e0b8 | ||
|
|
22243d1e49 | ||
|
|
bec0b7d4d0 | ||
|
|
f6f13c7fda | ||
|
|
e7068369fe | ||
|
|
b930d0731a | ||
|
|
2723223884 | ||
|
|
b6c116d4bf | ||
|
|
54e3f15dce | ||
|
|
c057847760 | ||
|
|
46c5764383 | ||
|
|
22ce36012e | ||
|
|
5c65e0cfa1 | ||
|
|
840e26b69a | ||
|
|
5e79652922 | ||
|
|
cb7b024e8f | ||
|
|
f3292a3651 | ||
|
|
76ccd332a6 | ||
|
|
3cd2c8532d | ||
|
|
c0739e908c | ||
|
|
379a947379 | ||
|
|
916a3d9066 | ||
|
|
b16b607b98 | ||
|
|
732d5bea10 | ||
|
|
d9a0d0ade2 | ||
|
|
e32ff0e1a6 | ||
|
|
5957156dee | ||
|
|
14f58ed6c7 | ||
|
|
038d57070b | ||
|
|
8a347248f5 | ||
|
|
caed086516 | ||
|
|
68927d4fd3 | ||
|
|
b2070a9407 | ||
|
|
8dacbdec3a | ||
|
|
2a110c91cf | ||
|
|
ba052beccd | ||
|
|
6f9c585452 | ||
|
|
18c26b90af | ||
|
|
ff49f797e5 | ||
|
|
c033a0d7c8 | ||
|
|
461f3c1004 | ||
|
|
90447d54d1 | ||
|
|
439d30a953 | ||
|
|
a972230b3a | ||
|
|
29a080dd9b | ||
|
|
0570cb8d9f | ||
|
|
6fa14bf029 | ||
|
|
4f0158b5e0 | ||
|
|
97add4d57a | ||
|
|
5b742571d3 | ||
|
|
a83043d735 | ||
|
|
22fcd616aa | ||
|
|
1a8188e1b4 | ||
|
|
f87fe4c3b4 | ||
|
|
f23f3ca907 | ||
|
|
965d99f1bc | ||
|
|
56ac054fb2 | ||
|
|
ced82cbac4 | ||
|
|
2fc1746ef5 | ||
|
|
10fc1f757c | ||
|
|
90009b9ec7 | ||
|
|
4367e03e46 | ||
|
|
c9634695a7 | ||
|
|
2a12b052f2 | ||
|
|
84b9502af4 | ||
|
|
694bdbc130 | ||
|
|
880cac2fdd | ||
|
|
a204b24fcf | ||
|
|
526e6b9fc7 | ||
|
|
f1ba6cb517 | ||
|
|
159cf0429c | ||
|
|
46b8dca360 | ||
|
|
4db998d357 | ||
|
|
0b843ada03 | ||
|
|
746c7ea8f7 | ||
|
|
5ed882faf2 | ||
|
|
fa4b10b4d9 | ||
|
|
cc51966ad1 | ||
|
|
c9d6344f2f | ||
|
|
acebafcbc2 | ||
|
|
4a1a2def95 | ||
|
|
09e352ef66 | ||
|
|
17976d7401 | ||
|
|
f25a9a4c80 | ||
|
|
cd2a5771b8 | ||
|
|
9c2ead90d5 | ||
|
|
a999c73ce0 | ||
|
|
b92173bf3d | ||
|
|
91823c41c5 | ||
|
|
c6bce636ee | ||
|
|
75a70bee6d | ||
|
|
1b1907af49 | ||
|
|
1b18eee5dc | ||
|
|
4931e48016 | ||
|
|
1b17acdb01 | ||
|
|
9c1cc5465d | ||
|
|
d8b5359fcb | ||
|
|
f96454adcc | ||
|
|
9da012568c | ||
|
|
9a20a258f5 | ||
|
|
10796457d2 | ||
|
|
78e659a142 | ||
|
|
2f50642ecb | ||
|
|
47bce4157d | ||
|
|
3a8a314566 | ||
|
|
050060b139 | ||
|
|
ddb678cc5b | ||
|
|
63c694f65f | ||
|
|
12093e6939 | ||
|
|
9949a6cd17 | ||
|
|
4600932d8c | ||
|
|
79ded3bb61 | ||
|
|
95145038b4 | ||
|
|
ce03293128 | ||
|
|
72e7271a14 | ||
|
|
0a8cfb8d2c | ||
|
|
0b07679ff2 | ||
|
|
550a5111b7 | ||
|
|
d162619bd3 | ||
|
|
5df14627fd | ||
|
|
fc3ce29845 | ||
|
|
bba800f2d6 | ||
|
|
fe2a1e1749 | ||
|
|
fc4ffd454e | ||
|
|
8dae4ad93a | ||
|
|
8da261f302 | ||
|
|
7bc7b5372e | ||
|
|
7d88e63bab | ||
|
|
a214fd1f78 | ||
|
|
79be097e34 | ||
|
|
11b0d36ba2 | ||
|
|
1234ee5fd2 | ||
|
|
80b73859a2 | ||
|
|
a548a77f26 | ||
|
|
d6bfb37e6a | ||
|
|
af305bf280 | ||
|
|
38a8d7fb2e | ||
|
|
0c70a0dcbf | ||
|
|
d16619fe86 | ||
|
|
ab6e1c2399 | ||
|
|
2dc85a5acd | ||
|
|
dbe1348b4c | ||
|
|
22846df03e | ||
|
|
d74536a4dc | ||
|
|
da20da264b | ||
|
|
22b9dfb9c9 | ||
|
|
27031ed688 | ||
|
|
e43c089ab8 | ||
|
|
d85b909054 | ||
|
|
75fd71d7e5 | ||
|
|
9efd64ab98 | ||
|
|
7aa01625d8 | ||
|
|
a3c58d7b70 | ||
|
|
ae466b1703 | ||
|
|
2564484429 | ||
|
|
93a044f587 | ||
|
|
81fe35ee2e | ||
|
|
08b6bdddf9 | ||
|
|
4d49db48a3 | ||
|
|
9b2266f68c | ||
|
|
752f425025 | ||
|
|
47262cd4ec | ||
|
|
47e64535d6 | ||
|
|
45d622e4bc | ||
|
|
249feaae7c | ||
|
|
9a27004ae5 | ||
|
|
42283150d7 | ||
|
|
5a1bcf9794 | ||
|
|
361cef4633 | ||
|
|
90ab746a42 | ||
|
|
e94cdcf29c | ||
|
|
1af046986d | ||
|
|
1c9263a25b | ||
|
|
fd6275a62b | ||
|
|
6b6790fc50 | ||
|
|
fb931087ab | ||
|
|
a2e1b32a1c | ||
|
|
54f89bce42 | ||
|
|
8b19d02e3b | ||
|
|
da7ad35577 | ||
|
|
937e893b6d | ||
|
|
d42a2d6494 | ||
|
|
8e8f4b1e5c | ||
|
|
298f71f2b1 | ||
|
|
2ba39b25f1 | ||
|
|
5c828b7e60 | ||
|
|
4640bea31a | ||
|
|
875361d7ce | ||
|
|
849bb5590a | ||
|
|
8d0c06e570 | ||
|
|
5b2fbf4f37 | ||
|
|
592dab2bdb | ||
|
|
51daa64e9a | ||
|
|
c0f9b0d8f6 | ||
|
|
505bba14eb | ||
|
|
ebbe24966c | ||
|
|
881c3f6e40 | ||
|
|
546aeab9f2 | ||
|
|
8de21e9bb7 | ||
|
|
2ecda74471 | ||
|
|
2136afde6b | ||
|
|
ea55db7286 | ||
|
|
819e8741cc | ||
|
|
6a5f77b278 | ||
|
|
8658a0d7dc | ||
|
|
c335aad25f | ||
|
|
9d9d647c1f | ||
|
|
d47a37fb76 | ||
|
|
24ec84851a | ||
|
|
0a3a15a66e | ||
|
|
2358ced061 | ||
|
|
2af5304884 | ||
|
|
5869fdf7f6 | ||
|
|
1a1d2ecfd9 | ||
|
|
5c356a4680 | ||
|
|
39af5d020e | ||
|
|
9ac64d0b92 | ||
|
|
7cc89b8b42 | ||
|
|
c6607724cb | ||
|
|
ebb37b0156 | ||
|
|
90dc04cf93 | ||
|
|
10cf492946 | ||
|
|
4d81eb021d | ||
|
|
83475008d9 | ||
|
|
03ac7ad730 | ||
|
|
cd50949a7e | ||
|
|
f0040c7b9a | ||
|
|
f8a0389e73 | ||
|
|
b436794773 | ||
|
|
1404319b28 | ||
|
|
90d22cbec6 | ||
|
|
33e2acfe61 | ||
|
|
db5fdfb0ee | ||
|
|
951cd73fe0 | ||
|
|
0eeb40b975 | ||
|
|
93272c13fd | ||
|
|
43abaeb055 | ||
|
|
18b9e661c9 | ||
|
|
f435d96241 | ||
|
|
d32e3f042f | ||
|
|
df5f95a5bd | ||
|
|
b0c475205b | ||
|
|
1e2219347e | ||
|
|
cbe1b8e266 | ||
|
|
2b12fe5773 | ||
|
|
a4fd6d38fb | ||
|
|
d20f22beb1 | ||
|
|
f4fe10844b | ||
|
|
122e89ffde | ||
|
|
c266739e9f | ||
|
|
96a4b3e5a5 | ||
|
|
7403226a97 | ||
|
|
fac8e76923 | ||
|
|
b864f5f5ba | ||
|
|
f9f66d787e | ||
|
|
bd211c87aa | ||
|
|
6c33e6e889 | ||
|
|
6fc25dae9e | ||
|
|
cfb6fd8b34 | ||
|
|
39d1a62f9e | ||
|
|
ba66fa7200 | ||
|
|
cb60663d49 | ||
|
|
0d2bf23d82 | ||
|
|
682a60e325 | ||
|
|
2ab6272cc7 | ||
|
|
152a6cd886 | ||
|
|
3c54d5df70 | ||
|
|
f91793e931 | ||
|
|
12925cd8b0 | ||
|
|
daac7cb90d | ||
|
|
a2d26b45bb | ||
|
|
dce8f3d25d | ||
|
|
38e5b6c1ad | ||
|
|
4859f5e1fa | ||
|
|
b9d7819faa | ||
|
|
ad2fbfe62d | ||
|
|
1f9323d086 | ||
|
|
574dbfded1 | ||
|
|
2a87387eb3 | ||
|
|
a5ddd10e31 | ||
|
|
e871cd8a44 | ||
|
|
7b431b37c7 | ||
|
|
eeef5ab4de | ||
|
|
ac4ec87942 | ||
|
|
290c2e0388 | ||
|
|
89924bda51 | ||
|
|
60eab3eb8c | ||
|
|
386401da60 | ||
|
|
31abe537a0 | ||
|
|
e0b61ceabd | ||
|
|
f9ecbdc70b | ||
|
|
30e3edb81d | ||
|
|
542e324869 | ||
|
|
1c5e5704f5 | ||
|
|
1d400dd98c | ||
|
|
a4ed3c2086 | ||
|
|
efb5caad22 | ||
|
|
3a002b6cf2 | ||
|
|
f8b7981be4 | ||
|
|
b55ee79d86 | ||
|
|
af70db88db | ||
|
|
7ef033f876 | ||
|
|
db59c07f27 | ||
|
|
9085e34d70 | ||
|
|
0dfa7d3af5 | ||
|
|
c28bf9ce24 | ||
|
|
5a1f1796d7 | ||
|
|
ffc95fcf0e | ||
|
|
b0e796ca83 | ||
|
|
3773e2ef95 | ||
|
|
00c1f67c57 | ||
|
|
3f19ba1554 | ||
|
|
f37cc2353d | ||
|
|
6a7bda6910 | ||
|
|
ff1b9930fc | ||
|
|
582da6df9a | ||
|
|
3bd830eacf | ||
|
|
f4efcbde5c | ||
|
|
658819bb71 | ||
|
|
3fc8249429 | ||
|
|
e0a38ce2c2 | ||
|
|
178e1789b5 | ||
|
|
108c900387 | ||
|
|
63507e8e29 | ||
|
|
87f1e06c41 | ||
|
|
7e8bafd217 | ||
|
|
457ad07ade | ||
|
|
c9ac9a75a6 | ||
|
|
79c901c220 | ||
|
|
b61d819fcb | ||
|
|
f4038e3674 | ||
|
|
8377514127 | ||
|
|
d8ea989eda | ||
|
|
5f3316d3dc | ||
|
|
a4fddb3fbe | ||
|
|
3d71716a8a | ||
|
|
9f37cef1bb | ||
|
|
0de1bbc85b | ||
|
|
3aa8624658 | ||
|
|
42b711b862 | ||
|
|
b25b798dbe | ||
|
|
2873dbe154 | ||
|
|
31a83cb0d8 | ||
|
|
383e384739 | ||
|
|
1bb6433649 | ||
|
|
ced39d0982 | ||
|
|
fc4d6a62af | ||
|
|
fa99cbbc73 | ||
|
|
49455721a3 | ||
|
|
11032b1936 | ||
|
|
e7ca4a69e3 | ||
|
|
f2fba51fe2 | ||
|
|
aca9fd3bed | ||
|
|
09f3f40462 | ||
|
|
e2525d8440 | ||
|
|
6769106881 | ||
|
|
0f324c8309 | ||
|
|
3af5e7e8da | ||
|
|
160f3ee4a7 | ||
|
|
3a310f19f0 | ||
|
|
d7a75dc026 | ||
|
|
f0a2c98376 | ||
|
|
282887d9c6 | ||
|
|
0e62cd11da | ||
|
|
599d23697d | ||
|
|
39b7c47e7b | ||
|
|
f6f03bc261 | ||
|
|
766fb56651 | ||
|
|
bec4610e12 | ||
|
|
184ebe72a2 | ||
|
|
2ad0bcbba9 | ||
|
|
88bb7cdca6 | ||
|
|
46de9460a6 | ||
|
|
92f64de115 | ||
|
|
f4baa86b71 |
+21
-11
@@ -17,7 +17,7 @@ AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: false
|
||||
AlwaysBreakTemplateDeclarations: true
|
||||
BinPackArguments: true
|
||||
BinPackParameters: true
|
||||
BraceWrapping:
|
||||
@@ -56,18 +56,29 @@ DisableFormat: false
|
||||
ExperimentalAutoDetectBinPacking: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
|
||||
# Include grouping/sorting
|
||||
SortIncludes: true
|
||||
IncludeBlocks: Regroup
|
||||
IncludeCategories:
|
||||
- Regex: '^"(llvm|llvm-c|clang|clang-c)/'
|
||||
Priority: 2
|
||||
- Regex: '^(<|"(gtest|gmock|isl|json)/)'
|
||||
Priority: 3
|
||||
- Regex: '.*'
|
||||
Priority: 1
|
||||
IncludeIsMainRegex: '(Test)?$'
|
||||
- Regex: '"(config_build|verilated_config|verilatedos)\.h"'
|
||||
Priority: -1 # Sepecials before main header
|
||||
- Regex: '(<|")verilated.*'
|
||||
Priority: 1 # Runtime headers
|
||||
- Regex: '"V3.*__gen.*\.h"'
|
||||
Priority: 3 # Generated internal headers separately
|
||||
- Regex: '"V3.*"'
|
||||
Priority: 2 # Internal header
|
||||
- Regex: '".*"'
|
||||
Priority: 4 # Other non-system headers
|
||||
- Regex: '<[[:alnum:]_.]+>'
|
||||
Priority: 5 # Simple system headers next
|
||||
- Regex: '<.*>'
|
||||
Priority: 6 # Other system headers next
|
||||
IncludeIsMainRegex: '$'
|
||||
|
||||
IndentCaseLabels: false
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
@@ -91,7 +102,6 @@ PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 60
|
||||
PointerAlignment: Left
|
||||
ReflowComments: true
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: true
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
|
||||
+13
-13
@@ -35,13 +35,13 @@ jobs:
|
||||
- { cc: gcc, cxx: g++ }
|
||||
m32: [0, 1]
|
||||
exclude:
|
||||
# Build pull requests only with ubuntu-20.04 and without m32
|
||||
# Build pull requests only with ubuntu-22.04 and without m32
|
||||
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
|
||||
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-22.04' || 'do-not-exclude' }}
|
||||
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
|
||||
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
|
||||
# Build -m32 only on ubuntu-20.04
|
||||
# Build -m32 only on ubuntu-22.04
|
||||
- {os: ubuntu-18.04, m32: 1}
|
||||
- {os: ubuntu-22.04, m32: 1}
|
||||
- {os: ubuntu-20.04, m32: 1}
|
||||
include:
|
||||
# Build GCC 10 on ubuntu-20.04
|
||||
- os: ubuntu-20.04
|
||||
@@ -61,12 +61,12 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: repo
|
||||
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||
with:
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
@@ -104,13 +104,13 @@ jobs:
|
||||
m32: [0, 1]
|
||||
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1]
|
||||
exclude:
|
||||
# Build pull requests only with ubuntu-20.04 and without m32
|
||||
# Build pull requests only with ubuntu-22.04 and without m32
|
||||
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
|
||||
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-22.04' || 'do-not-exclude' }}
|
||||
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
|
||||
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
|
||||
# Build -m32 only on ubuntu-20.04
|
||||
# Build -m32 only on ubuntu-22.04
|
||||
- {os: ubuntu-18.04, m32: 1}
|
||||
- {os: ubuntu-22.04, m32: 1}
|
||||
- {os: ubuntu-20.04, m32: 1}
|
||||
include:
|
||||
# Test with GCC 10 on ubuntu-20.04 without m32
|
||||
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0}
|
||||
@@ -132,7 +132,7 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
@@ -142,7 +142,7 @@ jobs:
|
||||
run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }}
|
||||
|
||||
- name: Cache $CCACHE_DIR
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v3
|
||||
env:
|
||||
CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache
|
||||
with:
|
||||
|
||||
@@ -11,7 +11,7 @@ on:
|
||||
jobs:
|
||||
Test:
|
||||
name: "'docs/CONTRIBUTORS' was signed"
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- run: test_regress/t/t_dist_contributors.pl
|
||||
|
||||
@@ -24,14 +24,14 @@ jobs:
|
||||
|
||||
|
||||
Build:
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
env:
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
CI_RUNS_ON: ubuntu-20.04
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
path: repo
|
||||
|
||||
@@ -46,7 +46,7 @@ jobs:
|
||||
run: tar --posix -c -z -f ${{ env.VERILATOR_ARCHIVE }} repo
|
||||
|
||||
- name: Upload tar archive
|
||||
uses: actions/upload-artifact@v2
|
||||
uses: actions/upload-artifact@v3
|
||||
with:
|
||||
path: ${{ github.workspace }}/${{ env.VERILATOR_ARCHIVE }}
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
@@ -73,15 +73,15 @@ jobs:
|
||||
- 9
|
||||
include:
|
||||
- { test: dist, num: '' }
|
||||
runs-on: ubuntu-20.04
|
||||
runs-on: ubuntu-22.04
|
||||
name: test-${{ matrix.test }}${{ matrix.num }}
|
||||
env:
|
||||
CI_BUILD_STAGE_NAME: test
|
||||
CI_RUNS_ON: ubuntu-20.04
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
steps:
|
||||
|
||||
- name: Download tar archive
|
||||
uses: actions/download-artifact@v2
|
||||
uses: actions/download-artifact@v3
|
||||
with:
|
||||
name: ${{ env.VERILATOR_ARCHIVE }}
|
||||
path: ${{ github.workspace }}
|
||||
|
||||
@@ -10,16 +10,16 @@ on:
|
||||
|
||||
jobs:
|
||||
format:
|
||||
runs-on: ubuntu-20.04
|
||||
name: Ubuntu 20.04 | format
|
||||
runs-on: ubuntu-22.04
|
||||
name: Ubuntu 22.04 | format
|
||||
env:
|
||||
CI_OS_NAME: linux
|
||||
CI_RUNS_ON: ubuntu-20.04
|
||||
CI_RUNS_ON: ubuntu-22.04
|
||||
CI_COMMIT: ${{ github.sha }}
|
||||
CI_M32: 0
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Install packages for build
|
||||
@@ -27,14 +27,14 @@ jobs:
|
||||
CI_BUILD_STAGE_NAME: build
|
||||
run: |
|
||||
bash ci/ci-install.bash &&
|
||||
sudo apt-get install clang-format-11 yapf3 &&
|
||||
sudo apt-get install clang-format-14 yapf3 &&
|
||||
git config --global user.email "[email protected]" &&
|
||||
git config --global user.name "github action"
|
||||
- name: Format code
|
||||
run: |
|
||||
autoconf &&
|
||||
./configure &&
|
||||
make -j 2 format CLANGFORMAT=clang-format-11 &&
|
||||
make -j 2 format CLANGFORMAT=clang-format-14 &&
|
||||
git status
|
||||
- name: Push
|
||||
run: |
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
\#*
|
||||
.#*
|
||||
.gdb_history
|
||||
.nfs*
|
||||
*~
|
||||
*.tidy
|
||||
|
||||
@@ -8,6 +8,165 @@ The changes in each Verilator version are described below. The
|
||||
contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
|
||||
Verilator 5.004 2022-12-14
|
||||
==========================
|
||||
|
||||
**Major:**
|
||||
|
||||
* Support named properties (#3667). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Add ENUMVALUE warning when value misused for enum (#726) (#3777) (#3783).
|
||||
* Deprecate --no-threads; use --threads 1 for single threaded (#3703). [Kamil Rakoczy, Antmicro Ltd]
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Support std::semaphore and typed std::mailbox (#3708). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Support 'with' in unique, unique_index, min, max in queues (#3772). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support events in VCD/FST traces (#3759). [Yves Mathieu]
|
||||
* Support foreach loops on strings (#3760). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support member selects in with clauses (#3775). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support super.new calls (#3789). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Support randcase.
|
||||
* Support pre_randomize and post_randomize.
|
||||
* Support $timeunit and $timeprecision.
|
||||
* Support assignment expressions.
|
||||
* Change ENDLABEL from warning into an error.
|
||||
* Internal AST improvements, also affect XML format (#3721). [Geza Lore]
|
||||
* Deprecate verilated_fst_sc.cpp and verilated_vcd_sc.cpp.
|
||||
* Disable stack size limit (#3706) (#3751). [Mariusz Glebocki]
|
||||
* Add error when use --exe with --lib-create (#3785). [Yinan Xu]
|
||||
* Fix jump handling in do while loops (#3731). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix 'with' clause handling in functions (#3739). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix CONTEXT compile error on mingw64 (#3741). [William D. Jones]
|
||||
* Fix MSVC compiler errors (#3742) (#3746). [Kritik Bhimani]
|
||||
* Fix CASEINCOMPLETE when covers all enum values (#3745) (#3782). [Guy-Armand Kamendje]
|
||||
* Fix return type of $countbits functions to int (#3725). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix timing control in while-break loops (#3733) (#3769). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix return in constructors (#3734). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix missing UNUSED warnings with --coverage (#3736). [alejandro-castro-ortegon]
|
||||
* Fix tracing parameters overridden with -G (#3723). [Iztok Jeras]
|
||||
* Fix folding of LogAnd with non-bool operands (#3726). [Geza Lore]
|
||||
* Fix Dfg optimization issues (#3740) (#3771). [Geza Lore]
|
||||
* Fix pre/postincrement operations (#3744) (#3756). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix cross-compile for MingW, Arm and RiscV (#3752). [Miodrag Milanović]
|
||||
* Fix $unit as base package for other packages (#3755). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix make jobserver with submakes (#3758). [Gus Smith]
|
||||
* Fix to escape VERILATOR_ROOT file paths (#3764) (#3765). [Jiacheng Qian]
|
||||
* Fix empty string literals converting to string types (#3774). [miree]
|
||||
* Fix to remove $date from .vcd files (#3779). [Larry Doolittle]
|
||||
* Fix missing user objects in --lib-create mode (#3780) (#3784). [Yinan Xu]
|
||||
* Fix non-blocking assignments in forks (#3781) (#3800). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix forks without any delayed statements (#3792) (#3801). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix internal error in bit op tree optimization (#3793). [Yutetsu TAKATSUKASA]
|
||||
* Fix lint_off EOFNEWLINE in .vlt files (#3796). [Andrew Nolte]
|
||||
* Fix wait 0.
|
||||
* Fix comparing ranged slices of unpacked arrays.
|
||||
|
||||
|
||||
Verilator 5.002 2022-10-29
|
||||
==========================
|
||||
|
||||
**Major:**
|
||||
|
||||
* This is a major new release.
|
||||
* Require C++20 for the new --timing features. Upgrading to a C++20 or
|
||||
newer compiler is strongly recommended.
|
||||
* Support the Active and NBA scheduling regions as defined by the
|
||||
SystemVerilog standard (IEEE 1800-2017 chapter 4). This means all generated
|
||||
clocks are now simulated correctly (#3278, #3384). [Geza Lore, Shunyao CAD]
|
||||
* Support timing controls (delays, event controls in any location, wait
|
||||
statements) and forks. [Krzysztof Bieganski, Antmicro Ltd]
|
||||
This may require adding --timing or --no-timing. See docs for details.
|
||||
* Introduce a new combinational logic optimizer (DFG), that can yield
|
||||
significant performance improvements on some designs. [Geza Lore, Shunyao CAD]
|
||||
* Add --binary option as alias of --main --exe --build --timing (#3625).
|
||||
For designs where C++ was only used to make a simple no-I/O testbench, we
|
||||
recommend abandoning that C++, and instead letting Verilator build it
|
||||
with --binary (or --main).
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Split UNUSED warning into genvar, param, and signal warnings (#3607). [Topa Topino]
|
||||
* Support standalone 'this' in classes (#2594) (#3248) (#3675). [Arkadiusz Kozdra, Antmicro Ltd]
|
||||
* Support tristate select/extend (#3604). [Ryszard Rozak, Antmicro Ltd>
|
||||
* Support linting for top module interfaces (#3635). [Kanad Kanhere]
|
||||
* Support virtual interfaces (#3654). [Arkadiusz Kozdra, Antmicro Ltd]
|
||||
* Support class type params without defaults (#3693). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Support empty generate_regions (#3695). [mpb27]
|
||||
* Support access to constructs inside type parameters (#3702). [Arkadiusz Kozdra, Antmicro Ltd]
|
||||
* Add --dump-tree-dot to enable dumping Ast Tree .dot files (#3636). [Marcel Chang]
|
||||
* Add --get-supported to determine what features are in Verilator.
|
||||
* Add error on real edge event control.
|
||||
* Fix false LATCH warning on 'unique if' (#3088). [Rachit Nigam]
|
||||
* Fix cell assigning integer array parameters (#3299). [Michael Platzer]
|
||||
* Fix LSB error on --hierarchical submodules (#3539). [danbone]
|
||||
* Fix $display of fixed-width numbers (#3565). [Iztok Jeras]
|
||||
* Fix foreach and pre/post increment in functions (#3613). [Nandu Raj]
|
||||
* Fix linker errors in user-facing timing functions (#3657). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix null access on optimized-out fork statements (#3658). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix VPI inline module naming mismatch (#3690) (#3694). [Jiuyang Liu]
|
||||
* Fix deadlock in timeprecision when using SystemC (#3707). [Kamil Rakoczy, Antmicro Ltd]
|
||||
* Fix width mismatch on inside operator (#3714). [Alex Torregrosa]
|
||||
|
||||
|
||||
Verilator 4.228 2022-10-01
|
||||
==========================
|
||||
|
||||
**Announcement:**
|
||||
|
||||
* The next release is anticipated to premiere Verilator Version 5. Please
|
||||
consider beta-testing the github 'develop-v5' branch, which will soon
|
||||
merge into the github 'master' branch (#3383).
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Support some IEEE signal strengths (#3601) (#3629). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Add --main to generate main() C++ (previously was experimental only).
|
||||
* Add --build-jobs, and rework arguments for -j (#3623). [Kamil Rakoczy]
|
||||
* Rename --bin to --build-dep-bin.
|
||||
* Rename debug flags --dumpi-tree, --dumpi-graph, etc. [Geza Lore]
|
||||
* Fix thread safety in SystemC VL_ASSIGN_SBW/WSB (#3494) (#3513). [Mladen Slijepcevic]
|
||||
* Fix crash in gate optimization of circular logic (#3543). [Bill Flynn]
|
||||
* Fix arguments in non-static method call (#3547) (#3582). [Gustav Svensk]
|
||||
* Fix default --mod-prefix when --prefix is repeated (#3603). [Geza Lore]
|
||||
* Fix calling trace() after open() segfault (#3610) (#3627). [Yu-Sheng Lin]
|
||||
* Fix typedef'ed class conversion to Boolean (#3616). [Aleksander Kiryk]
|
||||
* Fix Verilation speed when disabled warnings (#3632). [Kamil Rakoczy, Antmicro Ltd]
|
||||
|
||||
|
||||
Verilator 4.226 2022-08-31
|
||||
==========================
|
||||
|
||||
**Minor:**
|
||||
|
||||
* Add --future0 and --future1 options.
|
||||
* Support class parameters (#2231) (#3541). [Arkadiusz Kozdra, Antmicro Ltd]
|
||||
* Support wildcard index associative arrays (#3501). [Arkadiusz Kozdra, Antmicro Ltd]
|
||||
* Support negated properties (#3572). [Aleksander Kiryk]
|
||||
* Support $test$plusargs(expr) (#3489).
|
||||
* Rename trace rolloverSize() (#3570).
|
||||
* Improve Verilation speed with --threads on large designs. [Geza Lore]
|
||||
* Improve Verilation memory by reducing V3Number (#3521). [Mariusz Glebocki, Antmicro Ltd]
|
||||
* Fix struct pattern assignment (#2328) (#3517). [Mostafa Gamal]
|
||||
* Fix public combo propagation issues (#2905). [Todd Strader]
|
||||
* Fix incorrect tristate logic (#3399) [shareefj, Vighnesh Iyer]
|
||||
* Fix incorrect bit op tree optimization (#3470). [algrobman]
|
||||
* Fix bisonpre for MSYS2 (#3471).
|
||||
* Fix max memory usage (#3483). [Kamil Rakoczy, Antmicro Ltd]
|
||||
* Fix empty string arguments to display (#3484). [Grulfen]
|
||||
* Fix table optimizing away display (#3488). [Stefan Post]
|
||||
* Fix unique_ptr memory header for MinGW64 (#3493).
|
||||
* Fix $dump system task with --output-split-cfuncs (#3495) (#3497). [Varun Koyyalagunta]
|
||||
* Fix wrong bit op tree optimization (#3509). [Nathan Graybeal]
|
||||
* Fix nested default assignment for struct pattern (#3511) (#3524). [Mostafa Gamal]
|
||||
* Fix sformat string incorrectly cleared (#3515) (#3519). [Gustav Svensk]
|
||||
* Fix segfault exporting non-existent package (#3535).
|
||||
* Fix void-cast queue pop_front or pop_back (#3542) (#3364). [Drew Ranck]
|
||||
* Fix case statement comparing string literal (#3544). [Gustav Svensk]
|
||||
* Fix === with some tristate constants (#3551). [Ryszard Rozak, Antmicro Ltd]
|
||||
* Fix converting classes to string (#3552). [Arkadiusz Kozdra, Antmicro Ltd]
|
||||
* Fix --hierarchical with order-based pin connections (#3583) (#3585). [Kelin9298]
|
||||
|
||||
|
||||
Verilator 4.224 2022-06-19
|
||||
==========================
|
||||
|
||||
@@ -26,7 +185,7 @@ Verilator 4.224 2022-06-19
|
||||
* Improve conditional merging optimization (#3125). [Geza Lore, Shunyao CAD]
|
||||
* Define VM_TRACE_VCD when tracing in VCD format. [Geza Lore, Shunyao CAD]
|
||||
* Add assert when VerilatedContext is mis-deleted (#3121). [Rupert Swarbrick]
|
||||
* Internal prep work towards timing control. [Krzysztof Bieganski]
|
||||
* Internal prep work towards timing control. [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix hang with large case statement optimization (#3405). [Mike Urbach]
|
||||
* Fix UNOPTFLAT warning from initial static var (#3406). [Kamil Rakoczy]
|
||||
* Fix compile error when enable VL_LEAK_CHECKS (#3411). [HungMingWu]
|
||||
@@ -193,7 +352,7 @@ Verilator 4.212 2021-09-01
|
||||
* Fix re-evaluation of logic dependent on state set in DPI exports (#3091). [Geza Lore]
|
||||
* Support unpacked array localparams in tasks/functions (#3078). [Geza Lore]
|
||||
* Support timeunit/timeprecision in $unit.
|
||||
* Support assignment patterns as children of pins (#3041). [Krzysztof Bieganski]
|
||||
* Support assignment patterns as children of pins (#3041). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Add --instr-count-dpi to tune assumed DPI import cost for multithreaded
|
||||
model scheduling. Default value changed to 200 (#3068). [Yinan Xu]
|
||||
* Output files are split based on the set of headers required
|
||||
@@ -258,7 +417,7 @@ Verilator 4.204 2021-06-12
|
||||
* Prep work towards better ccache hashing/performance. [Geza Lore]
|
||||
* Fix assertion failure in bitOpTree optimization (#2891) (#2899). [Raynard Qiao]
|
||||
* Fix DPI functions not seen as vpiModule (#2893). [Todd Strader]
|
||||
* Fix bounds check in VL_SEL_IWII (#2910). [Krzysztof Bieganski]
|
||||
* Fix bounds check in VL_SEL_IWII (#2910). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Fix slowdown in elaboration (#2911). [Nathan Graybeal]
|
||||
* Fix initialization of assoc in assoc array (#2914). [myftptoyman]
|
||||
* Fix make support for gmake 3.x (#2920) (#2921). [Philipp Wagner]
|
||||
@@ -373,7 +532,7 @@ Verilator 4.108 2021-01-10
|
||||
**Major:**
|
||||
|
||||
* Many VPI changes for IEEE compatibility, which may alter behavior from previous releases.
|
||||
* Support randomize() class method and rand (#2607). [Krzysztof Bieganski]
|
||||
* Support randomize() class method and rand (#2607). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
|
||||
**Minor:**
|
||||
|
||||
@@ -433,7 +592,7 @@ Verilator 4.104 2020-11-14
|
||||
* Support queue and associative array 'with' statements (#2616).
|
||||
* Support queue slicing (#2326).
|
||||
* Support associative array pattern assignments and defaults.
|
||||
* Support static methods and typedefs in classes (#2615). [Krzysztof Bieganski]
|
||||
* Support static methods and typedefs in classes (#2615). [Krzysztof Bieganski, Antmicro Ltd]
|
||||
* Add error on typedef referencing self (#2539). [Cody Piersall]
|
||||
* With --debug, turn off address space layout randomization.
|
||||
* Fix iteration over mutating list bug in VPI (#2588). [Kaleb Barrett]
|
||||
@@ -2857,7 +3016,7 @@ Verilator 3.502 2005-11-30 Stable
|
||||
|
||||
* Fix local non-IO variables in public functions and tasks.
|
||||
* Fix bad lifetime optimization when same signal is assigned multiple
|
||||
times in both branch of a if. [Danny Ding]
|
||||
times in both branch of an if. [Danny Ding]
|
||||
|
||||
|
||||
Verilator 3.501 2005-11-16 Stable
|
||||
@@ -2997,8 +3156,8 @@ Verilator 3.450 2005-07-12
|
||||
* $finish will no longer exit, but set Verilated::gotFinish().
|
||||
This enables support for final statements, and for other cleanup code.
|
||||
If this is undesired, redefine the vl_user_finish routine. Top level
|
||||
loops should use Verilated::gotFinish() as a exit condition for their
|
||||
loop, and then call top->final(). To prevent a infinite loop, a double
|
||||
loops should use Verilated::gotFinish() as an exit condition for their
|
||||
loop, and then call top->final(). To prevent an infinite loop, a double
|
||||
$finish will still exit; this may be removed in future releases.
|
||||
* Support SystemVerilog keywords $bits, $countones, $isunknown,
|
||||
$onehot, $onehot0, always_comb, always_ff, always_latch, finish.
|
||||
@@ -3399,7 +3558,7 @@ Verilator 3.201-beta 2003-12-10
|
||||
**Major:**
|
||||
|
||||
* BETA VERSION, USE 3.124 for stable release!
|
||||
* Version 3.2XX includes a all new back-end.
|
||||
* Version 3.2XX includes an all new back-end.
|
||||
This includes automatic inlining, flattening of signals between
|
||||
hierarchy, and complete ordering of statements. This results in
|
||||
60-300% execution speedups, though less pretty C++ output. Even
|
||||
@@ -3428,7 +3587,7 @@ Verilator 3.124 2003-12-05
|
||||
|
||||
**Major:**
|
||||
|
||||
* A optimized executable will be made by default, in addition to a debug
|
||||
* An optimized executable will be made by default, in addition to a debug
|
||||
executable. Invoking Verilator with --debug will pick the debug version.
|
||||
|
||||
**Minor:**
|
||||
|
||||
+51
-23
@@ -107,6 +107,7 @@ SUBDIRS = docs src test_regress \
|
||||
examples/cmake_tracing_c \
|
||||
examples/cmake_tracing_sc \
|
||||
examples/cmake_protect_lib \
|
||||
examples/make_hello_binary \
|
||||
examples/make_hello_c \
|
||||
examples/make_hello_sc \
|
||||
examples/make_tracing_c \
|
||||
@@ -203,6 +204,7 @@ VL_INST_INC_BLDDIR_FILES = \
|
||||
# Files under srcdir, instead of build time
|
||||
VL_INST_INC_SRCDIR_FILES = \
|
||||
include/*.[chv]* \
|
||||
include/*.sv \
|
||||
include/gtkwave/*.[chv]* \
|
||||
include/vltstd/*.[chv]* \
|
||||
|
||||
@@ -243,6 +245,7 @@ installdata:
|
||||
; for p in $(VL_INST_INC_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
done
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_hello_binary
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_hello_c
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_hello_sc
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/make_tracing_c
|
||||
@@ -278,6 +281,7 @@ uninstall:
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include/gtkwave
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/make_hello_binary
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/make_hello_c
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/make_hello_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/make_tracing_c
|
||||
@@ -299,39 +303,63 @@ install-all: installbin installman installdata install-msg
|
||||
install-here: installman info
|
||||
|
||||
# Use --xml flag to see the cppcheck code to use for suppression
|
||||
CPPCHECK_CPP = $(wildcard \
|
||||
$(srcdir)/examples/*/*.cpp \
|
||||
$(srcdir)/include/*.cpp \
|
||||
$(srcdir)/src/*.cpp )
|
||||
CPPCHECK_H = $(wildcard \
|
||||
CPPCHECK1_CPP = $(wildcard $(srcdir)/include/*.cpp)
|
||||
CPPCHECK2_CPP = $(wildcard $(srcdir)/examples/*/*.cpp)
|
||||
CPPCHECK3_CPP = $(wildcard $(srcdir)/src/Vlc*.cpp)
|
||||
CPPCHECK4_CPP = $(wildcard $(srcdir)/src/V3[A-D]*.cpp $(srcdir)/src/Verilator*.cpp)
|
||||
CPPCHECK5_CPP = $(wildcard $(srcdir)/src/V3[E-I]*.cpp)
|
||||
CPPCHECK6_CPP = $(wildcard $(srcdir)/src/V3[P-Z]*.cpp)
|
||||
CPPCHECK7_CPP = $(wildcard $(srcdir)/src/V3[L-R]*.cpp)
|
||||
CPPCHECK8_CPP = $(wildcard $(srcdir)/src/V3[S-Z]*.cpp)
|
||||
CHECK_CPP = $(CPPCHECK1_CPP) $(CPPCHECK2_CPP) $(CPPCHECK3_CPP) $(CPPCHECK4_CPP) \
|
||||
$(CPPCHECK5_CPP) $(CPPCHECK6_CPP) $(CPPCHECK7_CPP) $(CPPCHECK8_CPP)
|
||||
CHECK_H = $(wildcard \
|
||||
$(srcdir)/include/*.h \
|
||||
$(srcdir)/src/*.h )
|
||||
CPPCHECK_YL = $(wildcard \
|
||||
CHECK_YL = $(wildcard \
|
||||
$(srcdir)/src/*.y \
|
||||
$(srcdir)/src/*.l )
|
||||
CPPCHECK = src/cppcheck_filtered cppcheck
|
||||
CPPCHECK_FLAGS = --enable=all --inline-suppr \
|
||||
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
|
||||
--suppress=nullPointerRedundantCheck
|
||||
--suppress=cstyleCast --suppress=useInitializationList \
|
||||
--suppress=nullPointer --suppress=nullPointerRedundantCheck --suppress=ctunullpointer \
|
||||
--suppress=unusedFunction --suppress=unusedScopedObject \
|
||||
--suppress=useStlAlgorithm
|
||||
CPPCHECK_FLAGS += --xml
|
||||
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CPPCHECK_CPP))
|
||||
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CHECK_CPP))
|
||||
CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
|
||||
|
||||
cppcheck: $(CPPCHECK_DEP)
|
||||
%.cppcheck: %.cpp
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
|
||||
cppcheck: cppcheck-1 cppcheck-2 cppcheck-3 cppcheck-4 cppcheck-5 cppcheck-6 cppcheck-7 cppcheck-8
|
||||
cppcheck-1:
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK1_CPP)
|
||||
cppcheck-2:
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK2_CPP)
|
||||
cppcheck-3:
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK3_CPP)
|
||||
cppcheck-4:
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK4_CPP)
|
||||
cppcheck-5:
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK5_CPP)
|
||||
cppcheck-6:
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK6_CPP)
|
||||
cppcheck-7:
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK7_CPP)
|
||||
cppcheck-8:
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK8_CPP)
|
||||
|
||||
CLANGTIDY = clang-tidy
|
||||
CLANGTIDY_FLAGS = -config='' -checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables'
|
||||
CLANGTIDY_DEP = $(subst .h,.h.tidy,$(CPPCHECK_H)) \
|
||||
$(subst .cpp,.cpp.tidy,$(CPPCHECK_CPP))
|
||||
CLANGTIDY_DEFS = -DVL_DEBUG=1 -DVL_THREADED=1 -DVL_CPPCHECK=1
|
||||
CLANGTIDY_FLAGS = -config='' \
|
||||
-header-filter='.*' \
|
||||
-checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables,-cppcoreguidelines-avoid-goto,-modernize-avoid-c-arrays,-readability-magic-numbers,-readability-simplify-boolean-expr,-cppcoreguidelines-macro-usage' \
|
||||
|
||||
CLANGTIDY_DEP = $(subst .cpp,.cpp.tidy,$(CHECK_CPP))
|
||||
CLANGTIDY_DEFS = -DVL_DEBUG=1 -DVL_CPPCHECK=1
|
||||
|
||||
clang-tidy: $(CLANGTIDY_DEP)
|
||||
%.cpp.tidy: %.cpp
|
||||
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) | 2>&1 tee $@
|
||||
%.h.tidy: %.h
|
||||
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) | 2>&1 tee $@
|
||||
$(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) -x c++-header | 2>&1 tee $@
|
||||
|
||||
analyzer-src:
|
||||
-rm -rf src/obj_dbg
|
||||
@@ -343,13 +371,13 @@ analyzer-include:
|
||||
|
||||
format: clang-format yapf format-pl-exec
|
||||
|
||||
CLANGFORMAT = clang-format-11
|
||||
CLANGFORMAT = clang-format-14
|
||||
CLANGFORMAT_FLAGS = -i
|
||||
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* test_regress/t/*.h
|
||||
CLANGFORMAT_FILES = $(CHECK_CPP) $(CHECK_H) $(CHECK_YL) test_regress/t/*.c* test_regress/t/*.h
|
||||
|
||||
clang-format:
|
||||
@$(CLANGFORMAT) --version | egrep 11.0 > /dev/null \
|
||||
|| echo "*** You are not using clang-format 11.0, indents may differ from master's ***"
|
||||
@$(CLANGFORMAT) --version | egrep 14.0 > /dev/null \
|
||||
|| echo "*** You are not using clang-format-14, indents may differ from master's ***"
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES)
|
||||
|
||||
PY_PROGRAMS = \
|
||||
@@ -388,10 +416,10 @@ yapf:
|
||||
FLAKE8 = flake8
|
||||
FLAKE8_FLAGS = \
|
||||
--extend-exclude=fastcov.py \
|
||||
--ignore=E123,E129,E251,E501,W503,W504,E701
|
||||
--ignore=E123,E129,E251,E402,E501,W503,W504,E701
|
||||
|
||||
PYLINT = pylint
|
||||
PYLINT_FLAGS = --disable=R0801
|
||||
PYLINT_FLAGS = --score=n --disable=R0801
|
||||
|
||||
lint-py:
|
||||
-$(FLAKE8) $(FLAKE8_FLAGS) $(PY_PROGRAMS)
|
||||
|
||||
+23
-22
@@ -28,11 +28,11 @@ Welcome to Verilator
|
||||
- |Logo|
|
||||
* - |verilator multithreaded performance|
|
||||
- **Fast**
|
||||
* Outperforms many commercial simulators
|
||||
* Single- and multi-threaded output models
|
||||
* Outperforms many closed-source commercial simulators
|
||||
* Single- and multithreaded output models
|
||||
* - **Widely Used**
|
||||
* Wide industry and academic deployment
|
||||
* Out-of-the-box support from Arm, and RISC-V vendor IP
|
||||
* Out-of-the-box support from Arm and RISC-V vendor IP
|
||||
- |verilator usage|
|
||||
* - |verilator community|
|
||||
- **Community Driven & Openly Licensed**
|
||||
@@ -52,23 +52,22 @@ What Verilator Does
|
||||
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
|
||||
"Verilates" the specified Verilog or SystemVerilog code by reading it,
|
||||
performing lint checks, and optionally inserting assertion checks and
|
||||
coverage-analysis points. It outputs single- or multi-threaded .cpp and .h
|
||||
coverage-analysis points. It outputs single- or multithreaded .cpp and .h
|
||||
files, the "Verilated" code.
|
||||
|
||||
The user writes a little C++/SystemC wrapper file, which instantiates the
|
||||
"Verilated" model of the user's top level module. These C++/SystemC files
|
||||
are then compiled by a C++ compiler (gcc/clang/MSVC++). Executing the
|
||||
resulting executable performs the design simulation. Verilator also
|
||||
supports linking Verilated generated libraries, optionally encrypted, into
|
||||
other simulators.
|
||||
These Verilated C++/SystemC files are then compiled by a C++ compiler
|
||||
(gcc/clang/MSVC++), optionally along with a user's own C++/SystemC wrapper
|
||||
file to instantiate the Verilated model. Executing the resulting executable
|
||||
performs the design simulation. Verilator also supports linking Verilated
|
||||
generated libraries, optionally encrypted, into other simulators.
|
||||
|
||||
Verilator may not be the best choice if you are expecting a full featured
|
||||
replacement for Incisive, ModelSim/Questa, VCS or another commercial
|
||||
Verilog simulator, or if you are looking for a behavioral Verilog simulator
|
||||
e.g. for a quick class project (we recommend `Icarus Verilog`_ for this.)
|
||||
However, if you are looking for a path to migrate SystemVerilog to C++ or
|
||||
SystemC, or your team is comfortable writing just a touch of C++ code,
|
||||
Verilator is the tool for you.
|
||||
Verilator may not be the best choice if you are expecting a full-featured
|
||||
replacement for a closed-source Verilog simulator, needs SDF annotation,
|
||||
mixed-signal simulation, or are doing a quick class project (we recommend
|
||||
`Icarus Verilog`_ for classwork.) However, if you are looking for a path
|
||||
to migrate SystemVerilog to C++/SystemC, or want high-speed simulation of
|
||||
synthesizable designs containing limited verification constructs, Verilator
|
||||
is the tool for you.
|
||||
|
||||
|
||||
Performance
|
||||
@@ -85,9 +84,11 @@ multithreading (yielding 200-1000x total over interpreted simulators).
|
||||
|
||||
Verilator has typically similar or better performance versus the
|
||||
closed-source Verilog simulators (Carbon Design Systems Carbonator,
|
||||
Modelsim, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic
|
||||
CVer/CVC). But, Verilator is open-sourced, so you can spend on computes
|
||||
rather than licenses. Thus Verilator gives you the best cycles/dollar.
|
||||
Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and
|
||||
Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on
|
||||
computes rather than licenses. Thus, Verilator gives you the best
|
||||
cycles/dollar.
|
||||
|
||||
|
||||
Installation & Documentation
|
||||
============================
|
||||
@@ -100,7 +101,7 @@ For more information:
|
||||
- `Verilator manual (HTML) <https://verilator.org/verilator_doc.html>`_,
|
||||
or `Verilator manual (PDF) <https://verilator.org/verilator_doc.pdf>`_
|
||||
|
||||
- `Subscribe to verilator announcements
|
||||
- `Subscribe to Verilator announcements
|
||||
<https://github.com/verilator/verilator-announce>`_
|
||||
|
||||
- `Verilator forum <https://verilator.org/forum>`_
|
||||
@@ -131,7 +132,7 @@ Related Projects
|
||||
- `GTKwave <http://gtkwave.sourceforge.net/>`_ - Waveform viewer for
|
||||
Verilator traces.
|
||||
|
||||
- `Icarus Verilog`_ - Icarus is a full featured interpreted Verilog
|
||||
- `Icarus Verilog`_ - Icarus is a full-featured interpreted Verilog
|
||||
simulator. If Verilator does not support your needs, perhaps Icarus may.
|
||||
|
||||
|
||||
|
||||
+75
-40
@@ -31,6 +31,7 @@ my $opt_gdb;
|
||||
my $opt_rr;
|
||||
my $opt_gdbbt;
|
||||
my $opt_quiet_exit;
|
||||
my $opt_unlimited_stack = 1;
|
||||
|
||||
# No arguments can't do anything useful. Give help
|
||||
if ($#ARGV < 0) {
|
||||
@@ -49,16 +50,17 @@ foreach my $sw (@ARGV) {
|
||||
Getopt::Long::config("no_auto_abbrev", "pass_through");
|
||||
if (! GetOptions(
|
||||
# Major operating modes
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
# "version!" => \&version, # Also passthru'ed
|
||||
"help" => \&usage,
|
||||
"debug" => \&debug,
|
||||
# "version!" => \&version, # Also passthru'ed
|
||||
# Switches
|
||||
"gdb!" => \$opt_gdb,
|
||||
"gdbbt!" => \$opt_gdbbt,
|
||||
"quiet-exit!" => \$opt_quiet_exit,
|
||||
"rr!" => \$opt_rr,
|
||||
"gdb!" => \$opt_gdb,
|
||||
"gdbbt!" => \$opt_gdbbt,
|
||||
"quiet-exit!" => \$opt_quiet_exit,
|
||||
"rr!" => \$opt_rr,
|
||||
"unlimited-stack!" => \$opt_unlimited_stack,
|
||||
# Additional parameters
|
||||
"<>" => sub {}, # Ignored
|
||||
"<>" => sub {}, # Ignored
|
||||
)) {
|
||||
pod2usage(-exitstatus => 2, -verbose => 0);
|
||||
}
|
||||
@@ -76,7 +78,8 @@ if ($opt_gdbbt && !gdb_works()) {
|
||||
my @quoted_sw = map { sh_escape($_) } @Opt_Verilator_Sw;
|
||||
if ($opt_gdb) {
|
||||
# Generic GDB interactive
|
||||
run (aslr_off()
|
||||
run (ulimit_stack_unlimited()
|
||||
. aslr_off()
|
||||
. ($ENV{VERILATOR_GDB} || "gdb")
|
||||
. " " . verilator_bin()
|
||||
# Note, uncomment to set breakpoints before running:
|
||||
@@ -92,12 +95,14 @@ if ($opt_gdb) {
|
||||
. " -ex 'bt'");
|
||||
} elsif ($opt_rr) {
|
||||
# Record with rr
|
||||
run (aslr_off()
|
||||
run (ulimit_stack_unlimited()
|
||||
. aslr_off()
|
||||
. "rr record " . verilator_bin()
|
||||
. " " . join(' ', @quoted_sw));
|
||||
} elsif ($opt_gdbbt && $Debug) {
|
||||
# Run under GDB to get gdbbt
|
||||
run (aslr_off()
|
||||
run (ulimit_stack_unlimited()
|
||||
. aslr_off()
|
||||
. "gdb"
|
||||
. " " . verilator_bin()
|
||||
. " --batch --quiet --return-child-result"
|
||||
@@ -106,10 +111,13 @@ if ($opt_gdb) {
|
||||
. " -ex 'bt' -ex 'quit'");
|
||||
} elsif ($Debug) {
|
||||
# Debug
|
||||
run(aslr_off() . verilator_bin() . " " . join(' ', @quoted_sw));
|
||||
run(ulimit_stack_unlimited()
|
||||
. aslr_off()
|
||||
. verilator_bin()
|
||||
. " " . join(' ', @quoted_sw));
|
||||
} else {
|
||||
# Normal, non gdb
|
||||
run(verilator_bin() . " " . join(' ', @quoted_sw));
|
||||
run(ulimit_stack_unlimited() . verilator_bin() . " " . join(' ', @quoted_sw));
|
||||
}
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
@@ -180,6 +188,17 @@ sub aslr_off {
|
||||
}
|
||||
}
|
||||
|
||||
sub ulimit_stack_unlimited {
|
||||
return "" if !$opt_unlimited_stack;
|
||||
system("ulimit -s unlimited 2>/dev/null");
|
||||
my $status = $?;
|
||||
if ($status == 0) {
|
||||
return "ulimit -s unlimited 2>/dev/null; exec ";
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
sub run {
|
||||
# Run command, check errors
|
||||
my $command = shift;
|
||||
@@ -244,6 +263,7 @@ Verilator - Translate and simulate SystemVerilog code using C++/SystemC
|
||||
|
||||
verilator --help
|
||||
verilator --version
|
||||
verilator --binary -j 0 [options] [source_files.v]... [opt_c_files.cpp/c/cc/a/o/so]
|
||||
verilator --cc [options] [source_files.v]... [opt_c_files.cpp/c/cc/a/o/so]
|
||||
verilator --sc [options] [source_files.v]... [opt_c_files.cpp/c/cc/a/o/so]
|
||||
verilator --lint-only -Wall [source_files.v]...
|
||||
@@ -267,7 +287,7 @@ detailed descriptions of these arguments.
|
||||
|
||||
=for VL_SPHINX_EXTRACT "_build/gen/args_verilator.rst"
|
||||
|
||||
<file.v> Verilog package, module and top module filenames
|
||||
<file.v> Verilog package, module, and top module filenames
|
||||
<file.c/cc/cpp> Optional C++ files to compile in
|
||||
<file.a/o/so> Optional C++ files to link in
|
||||
|
||||
@@ -282,35 +302,43 @@ detailed descriptions of these arguments.
|
||||
--autoflush Flush streams after all $displays
|
||||
--bbox-sys Blackbox unknown $system calls
|
||||
--bbox-unsup Blackbox unsupported language features
|
||||
--bin <filename> Override Verilator binary
|
||||
--binary Build model binary
|
||||
--build Build model executable/library after Verilation
|
||||
-CFLAGS <flags> C++ compiler arguments for makefile
|
||||
--build-dep-bin <filename> Override build dependency Verilator binary
|
||||
--build-jobs <jobs> Parallelism for --build
|
||||
--cc Create C++ output
|
||||
--cdc Clock domain crossing analysis
|
||||
-CFLAGS <flags> C++ compiler arguments for makefile
|
||||
--clk <signal-name> Mark specified signal as clock
|
||||
--make <build-tool> Generate scripts for specified build tool
|
||||
--no-clk <signal-name> Prevent marking specified signal as clock
|
||||
--compiler <compiler-name> Tune for specified C++ compiler
|
||||
--converge-limit <loops> Tune convergence settle time
|
||||
--coverage Enable all coverage
|
||||
--coverage-line Enable line coverage
|
||||
--coverage-max-width <width> Maximum array depth for coverage
|
||||
--coverage-toggle Enable toggle coverage
|
||||
--coverage-user Enable SVL user coverage
|
||||
--coverage-underscore Enable coverage of _signals
|
||||
--coverage-user Enable SVL user coverage
|
||||
-D<var>[=<value>] Set preprocessor define
|
||||
--debug Enable debugging
|
||||
--debug-check Enable debugging assertions
|
||||
--no-debug-leak Disable leaking memory in --debug mode
|
||||
--debugi <level> Enable debugging at a specified level
|
||||
--debugi-<srcfile> <level> Enable debugging a source file at a level
|
||||
--no-decoration Disable comments and symbol decorations
|
||||
--default-language <lang> Default language to parse
|
||||
+define+<var>=<value> Set preprocessor define
|
||||
--dpi-hdr-only Only produce the DPI header file
|
||||
--dump-defines Show preprocessor defines with -E
|
||||
--dump-tree Enable dumping .tree files
|
||||
--dump-treei <level> Enable dumping .tree files at a level
|
||||
--dump-treei-<srcfile> <level> Enable dumping .tree file at a source file at a level
|
||||
--dump-dfg Enable dumping DfgGraphs to .dot files
|
||||
--dump-graph Enable dumping V3Graphs to .dot files
|
||||
--dump-tree Enable dumping Ast .tree files
|
||||
--dump-tree-addrids Use short identifiers instead of addresses
|
||||
--dump-<srcfile> Enable dumping everything in source file
|
||||
--dumpi-dfg <level> Enable dumping DfgGraphs to .dot files at level
|
||||
--dumpi-graph <level> Enable dumping V3Graphs to .dot files at level
|
||||
--dumpi-tree <level> Enable dumping Ast .tree files at level
|
||||
--dumpi-<srcfile> <level> Enable dumping everything in source file at level
|
||||
-E Preprocess, but do not compile
|
||||
--error-limit <value> Abort after this number of errors
|
||||
--exe Link to create executable
|
||||
@@ -321,61 +349,60 @@ detailed descriptions of these arguments.
|
||||
--flatten Force inlining of all modules, tasks and functions
|
||||
-fno-<optimization> Disable internal optimization stage
|
||||
-G<name>=<value> Overwrite top-level parameter
|
||||
--gate-stmts <value> Tune gate optimizer depth
|
||||
--gdb Run Verilator under GDB interactively
|
||||
--gdbbt Run Verilator under GDB for backtrace
|
||||
--generate-key Create random key for --protect-key
|
||||
--getenv <var> Get environment variable with defaults
|
||||
--get-supported <feature> Get if feature is supported
|
||||
--help Display this help
|
||||
--hierarchical Enable hierarchical Verilation
|
||||
-I<dir> Directory to search for includes
|
||||
-j <jobs> Parallelism for --build
|
||||
--gate-stmts <value> Tune gate optimizer depth
|
||||
--if-depth <value> Tune IFDEPTH warning
|
||||
+incdir+<dir> Directory to search for includes
|
||||
--inline-mult <value> Tune module inlining
|
||||
--instr-count-dpi <value> Assumed dynamic instruction count of DPI imports
|
||||
-LDFLAGS <flags> Linker pre-object arguments for makefile
|
||||
-j <jobs> Parallelism for --build (alias to --build-jobs)
|
||||
--l2-name <value> Verilog scope name of the top module
|
||||
--language <lang> Default language standard to parse
|
||||
-LDFLAGS <flags> Linker pre-object arguments for makefile
|
||||
--lib-create <name> Create a DPI library
|
||||
+libext+<ext>+[ext]... Extensions for finding modules
|
||||
--lint-only Lint, but do not make output
|
||||
--make <build-tool> Generate scripts for specified build tool
|
||||
-MAKEFLAGS <flags> Arguments to pass to make during --build
|
||||
--main Generate C++ main() file
|
||||
--max-num-width <value> Maximum number width (default: 64K)
|
||||
--MMD Create .d dependency files
|
||||
--MP Create phony dependency targets
|
||||
--Mdir <directory> Name of output object directory
|
||||
--MMD Create .d dependency files
|
||||
--mod-prefix <topname> Name to prepend to lower classes
|
||||
--no-clk <signal-name> Prevent marking specified signal as clock
|
||||
--no-decoration Disable comments and symbol decorations
|
||||
--no-pins64 Don't use uint64_t's for 33-64 bit sigs
|
||||
--no-skip-identical Disable skipping identical output
|
||||
--MP Create phony dependency targets
|
||||
+notimingchecks Ignored
|
||||
-O0 Disable optimizations
|
||||
-O3 High performance optimizations
|
||||
-O3 High-performance optimizations
|
||||
-O<optimization-letter> Selectable optimizations
|
||||
-o <executable> Name of final executable
|
||||
--no-order-clock-delay Disable ordering clock enable assignments
|
||||
--no-verilate Skip verilation and just compile previously Verilated code.
|
||||
--output-split <statements> Split .cpp files into pieces
|
||||
--output-split-cfuncs <statements> Split model functions
|
||||
--output-split-ctrace <statements> Split tracing functions
|
||||
-P Disable line numbers and blanks with -E
|
||||
--pins-bv <bits> Specify types for top level ports
|
||||
--pins-sc-uint Specify types for top level ports
|
||||
--pins-sc-biguint Specify types for top level ports
|
||||
--pins-uint8 Specify types for top level ports
|
||||
--pins-bv <bits> 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-uint8 Specify types for top-level ports
|
||||
--no-pins64 Don't use uint64_t's for 33-64 bit sigs
|
||||
--pipe-filter <command> Filter all input through a script
|
||||
--pp-comments Show preprocessor comments with -E
|
||||
--prefix <topname> Name of top level class
|
||||
--prefix <topname> Name of top-level class
|
||||
--private Debugging; see docs
|
||||
--prof-c Compile C++ code with profiling
|
||||
--prof-cfuncs Name functions for profiling
|
||||
--prof-exec Enable generating execution profile for gantt chart
|
||||
--prof-pgo Enable generating profiling data for PGO
|
||||
--protect-key <key> Key for symbol protection
|
||||
--protect-ids Hash identifier names for obscurity
|
||||
--protect-key <key> Key for symbol protection
|
||||
--protect-lib <name> Create a DPI protected library
|
||||
--private Debugging; see docs
|
||||
--public Debugging; see docs
|
||||
--public-flat-rw Mark all variables, etc as public_flat_rw
|
||||
-pvalue+<name>=<value> Overwrite toplevel parameter
|
||||
@@ -386,6 +413,7 @@ detailed descriptions of these arguments.
|
||||
--rr Run Verilator and record with rr
|
||||
--savable Enable model save-restore
|
||||
--sc Create SystemC output
|
||||
--no-skip-identical Disable skipping identical output
|
||||
--stats Create statistics file
|
||||
--stats-vars Provide statistics on variables
|
||||
-sv Enable SystemVerilog parsing
|
||||
@@ -393,10 +421,12 @@ detailed descriptions of these arguments.
|
||||
--threads <threads> Enable multithreading
|
||||
--threads-dpi <mode> Enable multithreaded DPI
|
||||
--threads-max-mtasks <mtasks> Tune maximum mtask partitioning
|
||||
--timing Enable timing support
|
||||
--no-timing Disable timing support
|
||||
--timescale <timescale> Sets default timescale
|
||||
--timescale-override <timescale> Overrides all timescales
|
||||
--top <topname> Alias of --top-module
|
||||
--top-module <topname> Name of top level input module
|
||||
--top-module <topname> Name of top-level input module
|
||||
--trace Enable waveform creation
|
||||
--trace-coverage Enable tracing of coverage
|
||||
--trace-depth <levels> Depth of tracing
|
||||
@@ -408,11 +438,13 @@ detailed descriptions of these arguments.
|
||||
--trace-threads <threads> Enable FST waveform creation on separate threads
|
||||
--trace-underscore Enable tracing of _signals
|
||||
-U<var> Undefine preprocessor define
|
||||
--no-unlimited-stack Don't disable stack size limit
|
||||
--unroll-count <loops> Tune maximum loop iterations
|
||||
--unroll-stmts <stmts> Tune maximum loop body size
|
||||
--unused-regexp <regexp> Tune UNUSED lint signals
|
||||
-V Verbose version and config
|
||||
-v <filename> Verilog library
|
||||
--no-verilate Skip verilation and just compile previously Verilated code
|
||||
+verilog1995ext+<ext> Synonym for +1364-1995ext+<ext>
|
||||
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
|
||||
--version Displays program version and exits
|
||||
@@ -427,6 +459,9 @@ detailed descriptions of these arguments.
|
||||
-Wno-lint Disable all lint warnings
|
||||
-Wno-style Disable all style warnings
|
||||
-Wpedantic Warn on compliance-test issues
|
||||
-Wwarn-<message> Enable specified warning message
|
||||
-Wwarn-lint Enable lint warning message
|
||||
-Wwarn-style Enable style warning message
|
||||
--x-assign <mode> Assign non-initial Xs to this value
|
||||
--x-initial <mode> Assign initial Xs to this value
|
||||
--x-initial-edge Enable initial X->0 and X->1 edge triggers
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,C0114,C0115,C0116,C0123,C0301,R0902,R0913,R0914,R0912,R0915,W0621
|
||||
# pylint: disable=C0103,C0114,C0115,C0116,C0123,C0209,C0301,R0902,R0913,R0914,R0912,R0915,W0621
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,C0114,C0116
|
||||
# pylint: disable=C0103,C0114,C0116,C0209
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
@@ -38,7 +38,7 @@ def diff_dir(a, b):
|
||||
|
||||
anyfile = False
|
||||
for base in sorted(files.keys()):
|
||||
if (not 'a' in files[base]) or (not 'b' in files[base]):
|
||||
if ('a' not in files[base]) or ('b' not in files[base]):
|
||||
continue
|
||||
a = files[base]['a']
|
||||
b = files[base]['b']
|
||||
@@ -73,7 +73,7 @@ def diff_file(a, b):
|
||||
|
||||
def version_from(filename):
|
||||
# Return dump format
|
||||
with open(filename) as fh:
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
lineno = 0
|
||||
for line in fh:
|
||||
if lineno > 10:
|
||||
@@ -86,8 +86,8 @@ def version_from(filename):
|
||||
|
||||
def filterf(fn1, fn2):
|
||||
# Remove hex numbers before diffing
|
||||
with open(fn1) as fh1:
|
||||
with open(fn2, "w") as fh2:
|
||||
with open(fn1, "r", encoding="utf8") as fh1:
|
||||
with open(fn2, "w", encoding="utf8") as fh2:
|
||||
for line in fh1:
|
||||
if re.search(r' This=', line):
|
||||
continue
|
||||
|
||||
+5
-4
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,C0114,C0116,C0301,R0914,R0912,R0915,W0511,eval-used
|
||||
# pylint: disable=C0103,C0114,C0116,C0209,C0301,R0914,R0912,R0915,W0511,eval-used
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
@@ -29,7 +29,7 @@ def process(filename):
|
||||
|
||||
|
||||
def read_data(filename):
|
||||
with open(filename) as fh:
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
|
||||
re_record = re.compile(r'^VLPROFEXEC (\S+) (\d+)(.*)$')
|
||||
re_payload_mtaskBegin = re.compile(
|
||||
@@ -149,7 +149,8 @@ def report():
|
||||
for thread in Threads:
|
||||
# Make potentially multiple characters per column
|
||||
for start in Threads[thread]:
|
||||
if not Threads[thread][start]: continue
|
||||
if not Threads[thread][start]:
|
||||
continue
|
||||
cpu = Threads[thread][start]['cpu']
|
||||
elapsed = Threads[thread][start]['end'] - start
|
||||
if cpu not in Global['cpus']:
|
||||
@@ -317,7 +318,7 @@ def report_cpus():
|
||||
|
||||
def write_vcd(filename):
|
||||
print("Writing %s" % filename)
|
||||
with open(filename, "w") as fh:
|
||||
with open(filename, "w", encoding="utf8") as fh:
|
||||
vcd = {
|
||||
'values':
|
||||
collections.defaultdict(lambda: {}), # {<time>}{<code>} = value
|
||||
|
||||
+13
-14
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0103,C0114,C0116,R0914,R0912,R0915,eval-used
|
||||
# pylint: disable=C0103,C0114,C0116,C0209,R0914,R0912,R0915,eval-used
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
@@ -13,7 +13,7 @@ import re
|
||||
def profcfunc(filename):
|
||||
funcs = {}
|
||||
|
||||
with open(filename) as fh:
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
|
||||
for line in fh:
|
||||
# %time cumesec selfsec calls {stuff} name
|
||||
@@ -67,16 +67,15 @@ def profcfunc(filename):
|
||||
groups['design'] = collections.defaultdict(lambda: 0)
|
||||
groups['module'] = collections.defaultdict(lambda: 0)
|
||||
|
||||
for func in funcs:
|
||||
pct = funcs[func]['pct']
|
||||
for func, func_item in funcs.items():
|
||||
pct = func_item['pct']
|
||||
vfunc = func
|
||||
|
||||
funcarg = re.sub(r'^.*\(', '', func)
|
||||
|
||||
design = None
|
||||
for vde in verilated_mods:
|
||||
if verilated_mods[vde].match(func) or verilated_mods[vde].match(
|
||||
funcarg):
|
||||
for vde, vde_item in verilated_mods.items():
|
||||
if vde_item.match(func) or vde_item.match(funcarg):
|
||||
design = vde
|
||||
break
|
||||
|
||||
@@ -114,12 +113,12 @@ def profcfunc(filename):
|
||||
groups['module']['C++'] += pct
|
||||
|
||||
if vfunc not in vfuncs:
|
||||
vfuncs[vfunc] = funcs[func]
|
||||
vfuncs[vfunc] = func_item
|
||||
vfuncs[vfunc]['design'] = vdesign
|
||||
else:
|
||||
vfuncs[vfunc]['pct'] += funcs[func]['pct']
|
||||
vfuncs[vfunc]['calls'] += funcs[func]['calls']
|
||||
vfuncs[vfunc]['sec'] += funcs[func]['sec']
|
||||
vfuncs[vfunc]['pct'] += func_item['pct']
|
||||
vfuncs[vfunc]['calls'] += func_item['calls']
|
||||
vfuncs[vfunc]['sec'] += func_item['sec']
|
||||
|
||||
for ftype in ['type', 'design', 'module']:
|
||||
missing = 100
|
||||
@@ -136,9 +135,9 @@ def profcfunc(filename):
|
||||
print()
|
||||
|
||||
design_width = 1
|
||||
for func in vfuncs:
|
||||
if design_width < len(vfuncs[func]['design']):
|
||||
design_width = len(vfuncs[func]['design'])
|
||||
for func, func_item in vfuncs.items():
|
||||
if design_width < len(func_item['design']):
|
||||
design_width = len(func_item['design'])
|
||||
|
||||
print("Verilog code profile:")
|
||||
print(" These are split into three categories:")
|
||||
|
||||
@@ -19,6 +19,10 @@ set -x
|
||||
|
||||
cd $(dirname "$0")/..
|
||||
|
||||
# Avoid occasional cpan failures "Issued certificate has expired."
|
||||
export PERL_LWP_SSL_VERIFY_HOSTNAME=0
|
||||
echo "check_certificate = off" >> ~/.wgetrc
|
||||
|
||||
fatal() {
|
||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
FROM ubuntu:20.04
|
||||
FROM ubuntu:22.04
|
||||
|
||||
RUN apt-get update \
|
||||
&& DEBIAN_FRONTEND=noninteractive \
|
||||
|
||||
@@ -8,7 +8,7 @@ Verilator build. It uses the following parameters:
|
||||
|
||||
- Source revision (default: master)
|
||||
|
||||
- Compiler (GCC 9.3.0, clang 10.0.0, default: 9.3.0)
|
||||
- Compiler (GCC 10.3.0, clang 10.0.0, default: 10.3.0)
|
||||
|
||||
The container is published as ``verilator/verilator-buildenv`` on `docker
|
||||
hub
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
FROM ubuntu:20.04
|
||||
FROM ubuntu:22.04
|
||||
|
||||
RUN apt-get update \
|
||||
&& DEBIAN_FRONTEND=noninteractive \
|
||||
|
||||
@@ -62,12 +62,11 @@ Internals
|
||||
---------
|
||||
|
||||
The Dockerfile builds Verilator and removes the tree when completed to
|
||||
reduce the image size. The entrypoint is set as a wrapper script
|
||||
reduce the image size. The entrypoint is a wrapper script
|
||||
(``verilator-wrap.sh``). That script 1. calls Verilator, and 2. copies the
|
||||
Verilated runtime files to the ``obj_dir`` or the ``-Mdir``
|
||||
respectively. This allows the user to have the files to they may later
|
||||
build the C++ output with the matching runtime files. The wrapper also
|
||||
patches the Verilated Makefile accordingly.
|
||||
|
||||
There is also a hook defined that is run by docker hub via automated
|
||||
builds.
|
||||
A hook is also defined and run by Docker Hub via automated builds.
|
||||
|
||||
+36
-6
@@ -5,14 +5,14 @@
|
||||
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.224 2022-06-19],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
# When releasing, also update header of Changes file
|
||||
# and commit using "devel release" or "Version bump" message
|
||||
# Then 'make maintainer-dist'
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[5.004 2022-12-14],
|
||||
[https://verilator.org],
|
||||
[verilator],[https://verilator.org])
|
||||
|
||||
AC_CONFIG_HEADERS(src/config_build.h)
|
||||
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake)
|
||||
@@ -355,7 +355,7 @@ AC_SUBST(CFG_CXXFLAGS_PROFILE)
|
||||
#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++20)
|
||||
#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++20)
|
||||
case "$(which lsb_release 2>&1 > /dev/null && lsb_release -d)" in
|
||||
*Ubuntu*22.04*)
|
||||
*Arch*Linux* | *Ubuntu*22.04*)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++17)
|
||||
_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++17)
|
||||
;;
|
||||
@@ -374,6 +374,36 @@ _MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wlogical-op)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wthread-safety)
|
||||
AC_SUBST(CFG_CXXFLAGS_WEXTRA)
|
||||
|
||||
# Flags for coroutine support for dynamic scheduling
|
||||
_MY_CXX_CHECK_IFELSE(
|
||||
-fcoroutines-ts,
|
||||
[CFG_CXXFLAGS_COROUTINES="-fcoroutines-ts"],
|
||||
[CFG_CXXFLAGS_COROUTINES="-fcoroutines"])
|
||||
AC_SUBST(CFG_CXXFLAGS_COROUTINES)
|
||||
|
||||
# HAVE_COROUTINES
|
||||
# Check if coroutines are supported at all
|
||||
AC_MSG_CHECKING([whether coroutines are supported by $CXX])
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_COROUTINES"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([
|
||||
#ifdef __clang__
|
||||
#define __cpp_impl_coroutine 1
|
||||
#endif
|
||||
#include <coroutine>
|
||||
],[[]])],
|
||||
[_my_result=yes
|
||||
AC_DEFINE([HAVE_COROUTINES],[1],[Defined if coroutines are supported by $CXX])],
|
||||
[AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <experimental/coroutine>],[[]])],
|
||||
[_my_result=yes
|
||||
AC_DEFINE([HAVE_COROUTINES],[1],[Defined if coroutines are supported by $CXX])],
|
||||
[_my_result=no])])
|
||||
AC_MSG_RESULT($_my_result)
|
||||
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||
AC_SUBST(HAVE_COROUTINES)
|
||||
|
||||
# Flags for compiling Verilator internals including parser always
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Qunused-arguments)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-faligned-new)
|
||||
|
||||
@@ -44,15 +44,10 @@ Did you write a patch that fixes a bug?
|
||||
- Have your patch include the addition of your name to `docs/CONTRIBUTORS
|
||||
<CONTRIBUTORS>`__ (preferred).
|
||||
|
||||
- Use "git -s" as part of your commit. This adds a "signed-of-by"
|
||||
attribute which will certify your contribution as described in the
|
||||
`Signed-of-By convention
|
||||
<https://github.com/wking/signed-off-by/blob/master/Documentation/SubmittingPatches>`__.
|
||||
|
||||
- Email, or post in an issue a statement that you certify your
|
||||
contributions.
|
||||
|
||||
- In any of these cases your name will be added to `docs/CONTRIBUTORS
|
||||
- In any of these cases, your name will be added to `docs/CONTRIBUTORS
|
||||
<CONTRIBUTORS>`__ and you are agreeing all future contributions are
|
||||
also certified.
|
||||
|
||||
|
||||
@@ -5,11 +5,14 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
||||
|
||||
Adrien Le Masle
|
||||
Ahmed El-Mahmoudy
|
||||
Aleksander Kiryk
|
||||
Alex Chadwick
|
||||
Àlex Torregrosa
|
||||
Aliaksei Chapyzhenka
|
||||
Ameya Vikram Singh
|
||||
Andreas Kuster
|
||||
Andrew Nolte
|
||||
Arkadiusz Kozdra
|
||||
Chris Randall
|
||||
Chuxuan Wang
|
||||
Conor McCullough
|
||||
@@ -32,6 +35,8 @@ Gianfranco Costamagna
|
||||
Glen Gibb
|
||||
Graham Rushton
|
||||
Guokai Chen
|
||||
Gustav Svensk
|
||||
G-A. Kamendje
|
||||
Harald Heckmann
|
||||
Howard Su
|
||||
Huang Rui
|
||||
@@ -41,6 +46,7 @@ HyungKi Jeong
|
||||
Iru Cai
|
||||
Ivan Vnučec
|
||||
Iztok Jeras
|
||||
Jake Merdich
|
||||
James Hanlon
|
||||
James Hutchinson
|
||||
James Pallister
|
||||
@@ -49,6 +55,8 @@ Jamie Iles
|
||||
Jan Van Winkel
|
||||
Jean Berniolles
|
||||
Jeremy Bennett
|
||||
Jiacheng Qian
|
||||
Jiuyang Liu
|
||||
John Coiner
|
||||
John Demme
|
||||
Jonathan Drolet
|
||||
@@ -60,6 +68,7 @@ Kamil Rakoczy
|
||||
Kanad Kanhere
|
||||
Keith Colbert
|
||||
Kevin Kiningham
|
||||
Kritik Bhimani
|
||||
Krzysztof Bieganski
|
||||
Kuba Ober
|
||||
Larry Doolittle
|
||||
@@ -67,7 +76,9 @@ Ludwig Rogiers
|
||||
Lukasz Dalek
|
||||
Maarten De Braekeleer
|
||||
Maciej Sobkowski
|
||||
Marcel Chang
|
||||
Marco Widmer
|
||||
Mariusz Glebocki
|
||||
Markus Krause
|
||||
Marlon James
|
||||
Marshal Qiao
|
||||
@@ -78,12 +89,15 @@ Michael Killough
|
||||
Michaël Lefebvre
|
||||
Mike Popoloski
|
||||
Miodrag Milanović
|
||||
Mladen Slijepcevic
|
||||
Morten Borup Petersen
|
||||
Mostafa Gamal
|
||||
Nandu Raj
|
||||
Nathan Kohagen
|
||||
Nathan Myers
|
||||
Patrick Stewart
|
||||
Paul Wright
|
||||
Pawel Sagan
|
||||
Peter Horvath
|
||||
Peter Monsson
|
||||
Philipp Wagner
|
||||
@@ -95,6 +109,7 @@ Rafal Kapuscik
|
||||
Raynard Qiao
|
||||
Richard Myers
|
||||
Rupert Swarbrick
|
||||
Ryszard Rozak
|
||||
Samuel Riedel
|
||||
Sean Cross
|
||||
Sebastien Van Cauwenberghe
|
||||
@@ -108,17 +123,22 @@ Tobias Rosenkranz
|
||||
Tobias Wölfel
|
||||
Todd Strader
|
||||
Tomasz Gorochowik
|
||||
Topa Topino
|
||||
Tymoteusz Blazejczyk
|
||||
Udi Finkelstein
|
||||
Unai Martinez-Corral
|
||||
Varun Koyyalagunta
|
||||
Vassilis Papaefstathiou
|
||||
Veripool API Bot
|
||||
Victor Besyakov
|
||||
William D. Jones
|
||||
Wilson Snyder
|
||||
Xi Zhang
|
||||
Yinan Xu
|
||||
Yoda Lee
|
||||
Yossi Nivin
|
||||
Yuri Victorovich
|
||||
Yutetsu TAKATSUKASA
|
||||
Yu-Sheng Lin
|
||||
Yves Mathieu
|
||||
Zhanglei Wang
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0112,C0114,C0115,C0116,C0301,R0201,R0903
|
||||
# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0201,R0903
|
||||
# -*- Python -*- See copyright, etc below
|
||||
######################################################################
|
||||
|
||||
@@ -14,7 +14,7 @@ class VlSphinxExtract:
|
||||
SkipBasenames = {}
|
||||
|
||||
def process(self, filename):
|
||||
with open(filename) as fhr:
|
||||
with open(filename, "r", encoding="utf8") as fhr:
|
||||
fhw = None
|
||||
for line in fhr:
|
||||
# =for VL_SPHINX_EXTRACT "file_to_write_to"
|
||||
@@ -22,7 +22,7 @@ class VlSphinxExtract:
|
||||
if match:
|
||||
outname = match.group(1)
|
||||
print("Writing %s" % outname)
|
||||
fhw = open(outname, "w")
|
||||
fhw = open(outname, "w", encoding="utf8") # pylint: disable=consider-using-with
|
||||
fhw.write(
|
||||
".. comment: generated by vl_sphinx_extract from " +
|
||||
filename + "\n")
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
# pylint: disable=C0112,C0114,C0115,C0116,C0301,R0903
|
||||
# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0903
|
||||
# -*- Python -*- See copyright, etc below
|
||||
######################################################################
|
||||
|
||||
@@ -27,7 +27,7 @@ class VlSphinxFix:
|
||||
|
||||
def _edit(self, filename):
|
||||
is_html = re.search(r'\.(html)$', filename)
|
||||
with open(filename) as fhr:
|
||||
with open(filename, "r", encoding="utf8") as fhr:
|
||||
origfile = fhr.read()
|
||||
wholefile = origfile
|
||||
# Option doesn't like spaces, so we use
|
||||
@@ -43,7 +43,7 @@ class VlSphinxFix:
|
||||
if self.debug:
|
||||
print("Edit %s" % filename)
|
||||
tempname = filename + ".tmp"
|
||||
with open(tempname, "w") as fhw:
|
||||
with open(tempname, "w", encoding="utf8") as fhw:
|
||||
fhw.write(wholefile)
|
||||
os.rename(tempname, filename)
|
||||
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
.. comment: generated by t_lint_didnotconverge_bad
|
||||
.. code-block::
|
||||
|
||||
-V{t#,#}+ Vt_lint_didnotconverge_bad___024root___change_request
|
||||
-V{t#,#}+ Vt_lint_didnotconverge_bad___024root___change_request_1
|
||||
-V{t#,#} CHANGE: t/t_lint_didnotconverge_bad.v:14: a
|
||||
%Error: t/t_lint_didnotconverge_bad.v:7: Verilated model didn't converge
|
||||
-V{t#,#} 'stl' region trigger index 1 is active: @([hybrid] a)
|
||||
%Error: t/t_lint_didnotconverge_bad.v:7: Settle region did not converge.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.. comment: generated by t_lint_didnotconverge_nodbg_bad
|
||||
.. code-block::
|
||||
|
||||
%Error: t/t_lint_didnotconverge_bad.v:7: Verilated model didn't converge
|
||||
%Error: t/t_lint_didnotconverge_bad.v:7: Settle region did not converge.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
.. comment: generated by t_lint_stmtdly_bad
|
||||
.. code-block::
|
||||
|
||||
%Warning-STMTDLY: example.v:1:8 Unsupported: Ignoring delay on this delayed statement.
|
||||
%Warning-STMTDLY: example.v:1:7 Ignoring delay on this statement due to --no-timing
|
||||
|
||||
@@ -10,7 +10,7 @@ Revision History
|
||||
"Revision History" in the sidebar.
|
||||
|
||||
Changes are contained in the :file:`Changes` file of the distribution, and
|
||||
also summarized below. To subscribe to new versions see `Verilator
|
||||
also summarized below. To subscribe to new versions, see `Verilator
|
||||
Announcements <https://github.com/verilator/verilator-announce>`_.
|
||||
|
||||
.. include:: ../_build/gen/Changes
|
||||
|
||||
+2
-1
@@ -13,6 +13,7 @@ from datetime import datetime
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
|
||||
sys.path.insert(0, os.path.abspath('./_ext'))
|
||||
|
||||
import sphinx_rtd_theme # pylint: disable=wrong-import-position,
|
||||
@@ -20,7 +21,7 @@ import sphinx_rtd_theme # pylint: disable=wrong-import-position,
|
||||
|
||||
def get_vlt_version():
|
||||
filename = "../../Makefile"
|
||||
with open(filename) as fh:
|
||||
with open(filename, "r", encoding="utf8") as fh:
|
||||
for line in fh:
|
||||
match = re.search(r"PACKAGE_VERSION_NUMBER *= *([a-z0-9.]+)", line)
|
||||
if match:
|
||||
|
||||
+36
-61
@@ -51,8 +51,8 @@ also the instance of the top level instance in the design hierarchy (what
|
||||
you would refer to with :code:`$root` in SystemVerilog). This meant that
|
||||
all internal variables that were implemented by Verilator in the root scope
|
||||
were accessible as members of the model class itself. Note there were often
|
||||
many such variable due to module inlining, including :code:`/* verilator
|
||||
public_flat */` items.
|
||||
many such variable due to module inlining, including
|
||||
:code:`/* verilator public_flat */` items.
|
||||
|
||||
This means that user code that accesses internal signals in the model
|
||||
(likely including :code:`/* verilator public_flat */` signals, as they are
|
||||
@@ -86,61 +86,20 @@ Connecting to C++
|
||||
In C++ output mode (:vlopt:`--cc`), the Verilator generated model class is a
|
||||
simple C++ class. The user must write a C++ wrapper and main loop for the
|
||||
simulation, which instantiates the model class, and link with the Verilated
|
||||
model. Here is a simple example:
|
||||
model.
|
||||
|
||||
.. code-block:: C++
|
||||
Refer to ``examples/make_tracing_c`` in the distribution for a detailed
|
||||
commented example.
|
||||
|
||||
#include <verilated.h> // Defines common routines
|
||||
#include <iostream> // Need std::cout
|
||||
#include "Vtop.h" // From Verilating "top.v"
|
||||
Top level IO signals are read and written as members of the model. You
|
||||
call the model's :code:`eval()` method to evaluate the model. When the
|
||||
simulation is complete call the model's :code:`final()` method to execute
|
||||
any SystemVerilog final blocks, and complete any assertions. If using
|
||||
:vlopt:`--timing`, there are two additional functions for checking if
|
||||
there are any events pending in the simulation due to delays, and for
|
||||
retrieving the simulation time of the next delayed event. See
|
||||
:ref:`Evaluation Loop`.
|
||||
|
||||
Vtop *top; // Instantiation of model
|
||||
|
||||
uint64_t main_time = 0; // Current simulation time
|
||||
// This is a 64-bit integer to reduce wrap over issues and
|
||||
// allow modulus. This is in units of the timeprecision
|
||||
// used in Verilog (or from --timescale-override)
|
||||
|
||||
double sc_time_stamp() { // Called by $time in Verilog
|
||||
return main_time; // converts to double, to match
|
||||
// what SystemC does
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv); // Remember args
|
||||
|
||||
top = new Vtop; // Create model
|
||||
// Do not instead make Vtop as a file-scope static
|
||||
// variable, as the "C++ static initialization order fiasco"
|
||||
// may cause a crash
|
||||
|
||||
top->reset_l = 0; // Set some inputs
|
||||
|
||||
while (!Verilated::gotFinish()) {
|
||||
if (main_time > 10) {
|
||||
top->reset_l = 1; // Deassert reset
|
||||
}
|
||||
if ((main_time % 10) == 1) {
|
||||
top->clk = 1; // Toggle clock
|
||||
}
|
||||
if ((main_time % 10) == 6) {
|
||||
top->clk = 0;
|
||||
}
|
||||
top->eval(); // Evaluate model
|
||||
cout << top->out << endl; // Read a output
|
||||
main_time++; // Time passes...
|
||||
}
|
||||
|
||||
top->final(); // Done simulating
|
||||
// // (Though this example doesn't get here)
|
||||
delete top;
|
||||
}
|
||||
|
||||
|
||||
Note top level IO signals are read and written as members of the model. You
|
||||
call the :code:`eval()` method to evaluate the model. When the simulation is
|
||||
complete call the :code:`final()` method to execute any SystemVerilog final
|
||||
blocks, and complete any assertions. See :ref:`Evaluation Loop`.
|
||||
|
||||
|
||||
Connecting to SystemC
|
||||
@@ -447,16 +406,17 @@ accesses the above signal "readme" would be:
|
||||
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
|
||||
}
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
int main(int argc, char** argv) {
|
||||
Verilated::commandArgs(argc, argv);
|
||||
Vour* top = new Vour;
|
||||
Verilated::internalsDump(); // See scopes to help debug
|
||||
while (!Verilated::gotFinish()) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
const std::unique_ptr<Vour> top{new Vour{contextp.get()}};
|
||||
|
||||
contextp->internalsDump(); // See scopes to help debug
|
||||
while (!contextp->gotFinish()) {
|
||||
top->eval();
|
||||
VerilatedVpi::callValueCbs(); // For signal callbacks
|
||||
read_and_check();
|
||||
}
|
||||
delete top;
|
||||
return 0;
|
||||
}
|
||||
EOF
|
||||
@@ -483,10 +443,25 @@ there is only a single design, you would call :code:`eval_step()` then
|
||||
:code:`eval_end_step()`; in fact :code:`eval()` described above is just a
|
||||
wrapper which calls these two functions.
|
||||
|
||||
3. If using delays and :vlopt:`--timing`, there are two additional methods
|
||||
the user should call:
|
||||
|
||||
* :code:`designp->eventsPending()`, which returns :code:`true` if there are
|
||||
any delayed events pending,
|
||||
* :code:`designp->nextTimeSlot()`, which returns the simulation time of the
|
||||
next delayed event. This method can only be called if
|
||||
:code:`designp->nextTimeSlot()` returned :code:`true`.
|
||||
|
||||
Call :code:`eventsPending()` to check if you should continue with the
|
||||
simulation, and then :code:`nextTimeSlot()` to move simulation time forward.
|
||||
:vlopt:`--main` can be used with :vlopt:`--timing` to generate a basic example
|
||||
of a timing-enabled eval loop.
|
||||
|
||||
When :code:`eval()` (or :code:`eval_step()`) is called Verilator looks for
|
||||
changes in clock signals and evaluates related sequential always blocks,
|
||||
such as computing always_ff @ (posedge...) outputs. Then Verilator
|
||||
evaluates combinatorial logic.
|
||||
such as computing always_ff @ (posedge...) outputs. With :vlopt:`--timing`, it
|
||||
resumes any delayed processes awaiting the current simulation time. Then
|
||||
Verilator evaluates combinational logic.
|
||||
|
||||
Note combinatorial logic is not computed before sequential always blocks
|
||||
are computed (for speed reasons). Therefore it is best to set any non-clock
|
||||
|
||||
+109
-92
@@ -11,7 +11,7 @@ Authors
|
||||
When possible, please instead report bugs at `Verilator Issues
|
||||
<https://verilator.org/issues>`_.
|
||||
|
||||
Primary author is Wilson Snyder <[email protected]>.
|
||||
The primary author is Wilson Snyder <[email protected]>.
|
||||
|
||||
Major concepts by Paul Wasson, Duane Galbi, John Coiner, Geza Lore, Yutetsu
|
||||
Takatsukasa, and Jie Xu.
|
||||
@@ -22,122 +22,135 @@ Contributors
|
||||
|
||||
Many people have provided ideas and other assistance with Verilator.
|
||||
|
||||
Verilator is receiving major development support from the `CHIPS Alliance
|
||||
<https://chipsalliance.org>`_ and `Shunyao CAD <https://shunyaocad.com>`_.
|
||||
Verilator is receiving significant development support from the `CHIPS
|
||||
Alliance <https://chipsalliance.org>`_, `Antmicro Ltd
|
||||
<https://antmicro.com>`_ and `Shunyao CAD <https://shunyaocad.com>`_.
|
||||
|
||||
Previous major corporate sponsors of Verilator, by providing significant
|
||||
contributions of time or funds included include: Atmel Corporation, Cavium
|
||||
contributions of time or funds include: Atmel Corporation, Cavium
|
||||
Inc., Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd.,
|
||||
Hicamp Systems, Intel Corporation, Mindspeed Technologies Inc., MicroTune
|
||||
Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus Networks Inc.,
|
||||
SiCortex Inc, and Shunyao CAD.
|
||||
|
||||
The people who have contributed major functionality are: Byron Bradley,
|
||||
Jeremy Bennett, Lane Brooks, John Coiner, Duane Galbi, Geza Lore, Todd
|
||||
Strader, Stefan Wallentowitz, Paul Wasson, Jie Xu, and Wilson Snyder.
|
||||
Major testers included Jeff Dutton, Jonathon Donaldson, Ralf Karge, David
|
||||
Hewson, Iztok Jeras, Wim Michiels, Alex Solomatnikov, Sebastien Van
|
||||
Cauwenberghe, Gene Weber, and Clifford Wolf.
|
||||
The contributors of major functionality are: Krzysztof
|
||||
Bieganski, Byron Bradley, Jeremy Bennett, Lane Brooks, John Coiner, Duane
|
||||
Galbi, Geza Lore, Todd Strader, Stefan Wallentowitz, Paul Wasson, Jie Xu,
|
||||
and Wilson Snyder. Major testers included Jeff Dutton, Jonathon Donaldson,
|
||||
Ralf Karge, David Hewson, Iztok Jeras, Wim Michiels, Alex Solomatnikov,
|
||||
Sebastien Van Cauwenberghe, Gene Weber, and Clifford Wolf.
|
||||
|
||||
Some of the people who have provided ideas, and feedback for Verilator
|
||||
include: David Addison, Nikana Anastasiadis, Vasu Arasanipalai, Jens Arm,
|
||||
Tariq B. Ahmad, Sharad Bagri, Matthew Ballance, Andrew Bardsley, Matthew
|
||||
Barr, Geoff Barrett, Kaleb Barrett, Julius Baxter, Jeremy Bennett, Michael
|
||||
Berman, Jean Berniolles, Victor Besyakov, Moinak Bhattacharyya, Krzysztof
|
||||
Bieganski, David Binderman, Piotr Binkowski, Johan Bjork, David Black,
|
||||
Tymoteusz Blazejczyk, Daniel Bone, Morten Borup Petersen, Gregg Bouchard,
|
||||
Christopher Boumenot, Nick Bowler, Byron Bradley, Bryan Brady, Charlie
|
||||
Brej, J Briquet, Lane Brooks, John Brownlee, Jeff Bush, Lawrence Butcher,
|
||||
Tony Bybell, Iru Cai, Ted Campbell, Chris Candler, Lauren Carlson, Donal
|
||||
Casey, Alex Chadwick, Terry Chen, Yi-Chung Chen, Enzo Chi, Robert A. Clark,
|
||||
Ryan Clarke, Allan Cochrane, John Coiner, Gianfranco Costamagna, Sean
|
||||
Cross, George Cuan, Joe DErrico, Lukasz Dalek, Gunter Dannoritzer, Ashutosh
|
||||
Das, Maarten De Braekeleer, Bernard Deadman, Alberto Del Rio, John Demme,
|
||||
Mike Denio, John Deroo, Philip Derrick, John Dickol, Ruben Diez, Danny
|
||||
Ding, Jacko Dirks, Ivan Djordjevic, Jonathon Donaldson, Sebastian Dressler,
|
||||
Alex Duller, Jeff Dutton, Tomas Dzetkulic, Richard E George, Edgar
|
||||
E. Iglesias, Usuario Eda, Charles Eddleston, Chandan Egbert, Jan Egil Ruud,
|
||||
Joe Eiler, Ahmed El-Mahmoudy, Trevor Elbourne, Mats Engstrom, Charles Eric
|
||||
LaForest, Robert Farrell, Eugen Fekete, Fabrizio Ferrandi, Udi Finkelstein,
|
||||
Brian Flachs, Andrea Foletto, Bob Fredieu, Duane Galbi, Benjamin Gartner,
|
||||
Christian Gelinek, Peter Gerst, Glen Gibb, Michael Gielda, Barbara Gigerl,
|
||||
Shankar Giri, Dan Gisselquist, Petr Gladkikh, Sam Gladstone, Andrew
|
||||
Goessling, Amir Gonnen, Chitlesh Goorah, Tomasz Gorochowik, Kai Gossner,
|
||||
Sergi Granell, Al Grant, Alexander Grobman, Xuan Guo, Driss Hafdi, Neil
|
||||
include:
|
||||
|
||||
David Addison, Tariq B. Ahmad, Nikana Anastasiadis, Vasu Arasanipalai, Jens
|
||||
Arm, Sharad Bagri, Matthew Ballance, Andrew Bardsley, Matthew Barr, Geoff
|
||||
Barrett, Kaleb Barrett, Julius Baxter, Jeremy Bennett, Michael Berman, Jean
|
||||
Berniolles, Victor Besyakov, Moinak Bhattacharyya, Krzysztof Bieganski,
|
||||
David Binderman, Piotr Binkowski, Johan Bjork, David Black, Tymoteusz
|
||||
Blazejczyk, Daniel Bone, Gregg Bouchard, Christopher Boumenot, Nick Bowler,
|
||||
Byron Bradley, Bryan Brady, Maarten De Braekeleer, Charlie Brej, J Briquet,
|
||||
Lane Brooks, John Brownlee, Jeff Bush, Lawrence Butcher, Tony Bybell, Iru
|
||||
Cai, Ted Campbell, Chris Candler, Lauren Carlson, Donal Casey, Alex
|
||||
Chadwick, Marcel Chang, Aliaksei Chapyzhenka, Guokai Chen, Terry Chen,
|
||||
Yi-Chung Chen, Enzo Chi, Robert A. Clark, Ryan Clarke, Allan Cochrane, John
|
||||
Coiner, Keith Colbert, Gianfranco Costamagna, Sean Cross, George Cuan, Joe
|
||||
DErrico, Lukasz Dalek, Gunter Dannoritzer, Ashutosh Das, Bernard Deadman,
|
||||
John Demme, Mike Denio, John Deroo, Philip Derrick, John Dickol, Ruben
|
||||
Diez, Danny Ding, Jacko Dirks, Ivan Djordjevic, Jonathon Donaldson, Larry
|
||||
Doolittle, Sebastian Dressler, Jonathan Drolet, Alex Duller, Jeff Dutton,
|
||||
Tomas Dzetkulic, Usuario Eda, Charles Eddleston, Chandan Egbert, Joe Eiler,
|
||||
Ahmed El-Mahmoudy, Trevor Elbourne, Mats Engstrom, Robert Farrell, Eugen
|
||||
Fekete, Fabrizio Ferrandi, Udi Finkelstein, Brian Flachs, Bill Flynn,
|
||||
Andrea Foletto, Bob Fredieu, Duane Galbi, Mostafa Gamal, Benjamin Gartner,
|
||||
Christian Gelinek, Richard E George, Peter Gerst, Glen Gibb, Michael
|
||||
Gielda, Barbara Gigerl, Shankar Giri, Dan Gisselquist, Petr Gladkikh, Sam
|
||||
Gladstone, Mariusz Glebocki, Andrew Goessling, Amir Gonnen, Chitlesh
|
||||
Goorah, Tomasz Gorochowik, Kai Gossner, Sergi Granell, Al Grant, Nathan
|
||||
Graybeal, Alexander Grobman, Graham Rushton, Xuan Guo, Driss Hafdi, Neil
|
||||
Hamilton, James Hanlon, Oyvind Harboe, Jannis Harder, Junji Hashimoto,
|
||||
Thomas Hawkins, Mitch Hayenga, Harald Heckmann, Robert Henry, Stephen
|
||||
Henry, David Hewson, Jamey Hicks, Joel Holdsworth, Andrew Holme, Hiroki
|
||||
Honda, Alex Hornung, Pierre-Henri Horrein, David Horton, Peter Horvath, Jae
|
||||
Hossell, Kuoping Hsu, Alan Hunter, James Hutchinson, Anderson Ignacio da
|
||||
Silva, Jamie Iles, Thomas J Whatson, Ben Jackson, Mark Jackson Pulver,
|
||||
Shareef Jalloq, Marlon James, Krzysztof Jankowski, HyungKi Jeong, Iztok
|
||||
Jeras, James Johnson, Christophe Joly, Franck Jullien, James Jung, Mike
|
||||
Kagen, Arthur Kahlich, Kaalia Kahn, Guy-Armand Kamendje, Vasu Kandadi,
|
||||
Kanad Kanhere, Patricio Kaplan, Pieter Kapsenberg, Rafal Kapuscik, Ralf
|
||||
Karge, Dan Katz, Sol Katzman, Ian Kennedy, Michael Killough, Jonathan
|
||||
Kimmitt, Olof Kindgren, Kevin Kiningham, Dan Kirkham, Sobhan Klnv, Gernot
|
||||
Koch, Jack Koenig, Soon Koh, Nathan Kohagen, Steve Kolecki, Brett Koonce,
|
||||
Will Korteland, Wojciech Koszek, Varun Koyyalagunta, Markus Krause, David
|
||||
Kravitz, Roland Kruse, Andreas Kuster, Sergey Kvachonok, Ed Lander, Steve
|
||||
Lang, Stephane Laurent, Walter Lavino, Christian Leber, Larry Lee, Igor
|
||||
Lesik, John Li, Eivind Liland, Charlie Lind, Andrew Ling, Jiuyang Liu, Paul
|
||||
Liu, Derek Lockhart, Jake Longo, Geza Lore, Arthur Low, Stefan Ludwig, Dan
|
||||
Lussier, Fred Ma, Duraid Madina, Odd Magne Reitan, Affe Mao, Julien
|
||||
Margetts, Mark Marshall, Alfonso Martinez, Unai Martinez-Corral, Yves
|
||||
Mathieu, Patrick Maupin, Conor McCullough, Jason McMullan, Elliot Mednick,
|
||||
Wim Michiels, Miodrag Milanovic, Peter Monsson, Sean Moore, Dennis
|
||||
Muhlestein, John Murphy, Matt Myers, Nathan Myers, Richard Myers, Dimitris
|
||||
Nalbantis, Peter Nelson, Bob Newgard, Paul Nitza, Yossi Nivin, Pete Nixon,
|
||||
Lisa Noack, Mark Nodine, Kuba Ober, Andreas Olofsson, Baltazar Ortiz,
|
||||
Aleksander Osman, Don Owen, James Pallister, Vassilis Papaefstathiou, Brad
|
||||
Parker, Dan Petrisko, Maciej Piechotka, David Pierce, Cody Piersall,
|
||||
Dominic Plunkett, David Poole, Mike Popoloski, Roman Popov, Rich Porter,
|
||||
Niranjan Prabhu, Usha Priyadharshini, Prateek Puri, Marshal Qiao, Nandu
|
||||
Raj, Danilo Ramos, Chris Randall, Anton Rapp, Josh Redford, Frederic
|
||||
Requin, Dustin Richmond, Samuel Riedel, Eric Rippey, Oleg Rodionov, Ludwig
|
||||
Rogiers, Paul Rolfe, Arjen Roodselaar, Tobias Rosenkranz, Huang Rui, Denis
|
||||
Rystsov, John Sanguinetti, Galen Seitz, Joseph Shaker, Salman Sheikh, Yu
|
||||
Sheng Lin, Hao Shi, Mike Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Fan
|
||||
Shupei, Rodney Sinclair, Steven Slatter, Brian Small, Garrett Smith, Tim
|
||||
Snyder, Wilson Snyder, Maciej Sobkowski, Stan Sokorac, Alex Solomatnikov,
|
||||
Wei Song, Art Stamness, David Stanford, John Stevenson, Pete Stevenson,
|
||||
Patrick Stewart, Rob Stoddard, Todd Strader, John Stroebel, Sven Stucki,
|
||||
Howard Su, Emerson Suguimoto, Gene Sullivan, Wai Sum Mong, Qingyao Sun,
|
||||
Renga Sundararajan, Rupert Swarbrick, Yutetsu Takatsukasa, Thierry Tambe,
|
||||
Drew Taussig, Peter Tengstrand, Wesley Terpstra, Rui Terra, Stefan Thiede,
|
||||
Gary Thomas, Ian Thompson, Kevin Thompson, Mike Thyer, Hans Tichelaar,
|
||||
Viktor Tomov, Steve Tong, Alex Torregrosa, Michael Tresidder, David Turner,
|
||||
Neil Turton, Cong Van Nguyen, Hans Van Antwerpen, Jan Van Winkel, Sebastien
|
||||
Van Cauwenberghe, Laurens van Dam, Leendert van Doorn, Srini Vemuri, Yuri
|
||||
Hossell, Kuoping Hsu, Teng Huang, Steven Hugg, Alan Hunter, James
|
||||
Hutchinson, Ehab Ibrahim, Edgar E. Iglesias, Jamie Iles, Vighnesh Iyer, Ben
|
||||
Jackson, Shareef Jalloq, Marlon James, Krzysztof Jankowski, HyungKi Jeong,
|
||||
Iztok Jeras, Alexandre Joannou, James Johnson, Christophe Joly, Franck
|
||||
Jullien, James Jung, Mike Kagen, Arthur Kahlich, Kaalia Kahn, Guy-Armand
|
||||
Kamendje, Vasu Kandadi, Kanad Kanhere, Patricio Kaplan, Pieter Kapsenberg,
|
||||
Rafal Kapuscik, Ralf Karge, Per Karlsson, Dan Katz, Sol Katzman, Ian
|
||||
Kennedy, Michael Killough, Sun Kim, Jonathan Kimmitt, Olof Kindgren, Kevin
|
||||
Kiningham, Dan Kirkham, Aleksander Kiryk, Sobhan Klnv, Gernot Koch, Jack
|
||||
Koenig, Soon Koh, Nathan Kohagen, Steve Kolecki, Brett Koonce, Will
|
||||
Korteland, Wojciech Koszek, Varun Koyyalagunta, Arkadiusz Kozdra, Markus
|
||||
Krause, David Kravitz, Roland Kruse, Andreas Kuster, Sergey Kvachonok,
|
||||
Charles Eric LaForest, Ed Lander, Steve Lang, Stephane Laurent, Walter
|
||||
Lavino, Christian Leber, Larry Lee, Yoda Lee, Michaël Lefebvre, Igor Lesik,
|
||||
John Li, Eivind Liland, Yu Sheng Lin, Charlie Lind, Andrew Ling, Jiuyang
|
||||
Liu, Paul Liu, Derek Lockhart, Jake Longo, Geza Lore, Arthur Low, Stefan
|
||||
Ludwig, Dan Lussier, Fred Ma, Duraid Madina, Affe Mao, Julien Margetts,
|
||||
Mark Marshall, Alfonso Martinez, Unai Martinez-Corral, Adrien Le Masle,
|
||||
Yves Mathieu, Patrick Maupin, Conor McCullough, Jason McMullan, Elliot
|
||||
Mednick, David Metz, Wim Michiels, Miodrag Milanovic, Kevin Millis, Wai Sum
|
||||
Mong, Peter Monsson, Sean Moore, Dennis Muhlestein, John Murphy, Matt
|
||||
Myers, Nathan Myers, Richard Myers, Dimitris Nalbantis, Peter Nelson, Bob
|
||||
Newgard, Rachit Nigam, Paul Nitza, Yossi Nivin, Pete Nixon, Lisa Noack,
|
||||
Mark Nodine, Kuba Ober, Andreas Olofsson, Baltazar Ortiz, Aleksander Osman,
|
||||
Don Owen, James Pallister, Vassilis Papaefstathiou, Brad Parker, Morten
|
||||
Borup Petersen, Dan Petrisko, Maciej Piechotka, David Pierce, Cody
|
||||
Piersall, Michael Platzer, Dominic Plunkett, David Poole, Mike Popoloski,
|
||||
Roman Popov, Rich Porter, Stefan Post, Niranjan Prabhu, Damien Pretet, Usha
|
||||
Priyadharshini, Mark Jackson Pulver, Prateek Puri, Marshal Qiao, Nandu Raj,
|
||||
Kamil Rakoczy, Danilo Ramos, Drew Ranck, Chris Randall, Anton Rapp, Josh
|
||||
Redford, Odd Magne Reitan, Frederic Requin, Dustin Richmond, Samuel Riedel,
|
||||
Alberto Del Rio, Eric Rippey, Oleg Rodionov, Ludwig Rogiers, Paul Rolfe,
|
||||
Arjen Roodselaar, Tobias Rosenkranz, Ryszard Rozak, Huang Rui, Graham
|
||||
Rushton, Jan Egil Ruud, Denis Rystsov, John Sanguinetti, Martin Schmidt,
|
||||
Julie Schwartz, Galen Seitz, Joseph Shaker, Salman Sheikh, Hao Shi, Mike
|
||||
Shinkarovsky, Rafael Shirakawa, Jeffrey Short, Fan Shupei, Anderson Ignacio
|
||||
da Silva, Rodney Sinclair, Ameya Vikram Singh, Steven Slatter, Mladen
|
||||
Slijepcevic, Brian Small, Garrett Smith, Tim Snyder, Wilson Snyder, Maciej
|
||||
Sobkowski, Stan Sokorac, Alex Solomatnikov, Flavien Solt, Wei Song, Trefor
|
||||
Southwell, Martin Stadler, Art Stamness, David Stanford, John Stevenson,
|
||||
Pete Stevenson, Patrick Stewart, Rob Stoddard, Todd Strader, John Stroebel,
|
||||
Sven Stucki, Howard Su, Emerson Suguimoto, Gene Sullivan, Qingyao Sun,
|
||||
Renga Sundararajan, Gustav Svensk, Rupert Swarbrick, Yutetsu Takatsukasa,
|
||||
Thierry Tambe, Drew Taussig, Jose Tejada, Peter Tengstrand, Wesley
|
||||
Terpstra, Rui Terra, Stefan Thiede, Gary Thomas, Ian Thompson, Kevin
|
||||
Thompson, Mike Thyer, Hans Tichelaar, Viktor Tomov, Steve Tong, Topa
|
||||
Topino, Alex Torregrosa, Michael Tresidder, David Turner, Neil Turton, Mike
|
||||
Urbach, Hans Van Antwerpen, Sebastien Van Cauwenberghe, Laurens van Dam,
|
||||
Leendert van Doorn, Cong Van Nguyen, Jan Van Winkel, Srini Vemuri, Yuri
|
||||
Victorovich, Bogdan Vukobratovic, Holger Waechtler, Philipp Wagner, Stefan
|
||||
Wallentowitz, Shawn Wang, Paul Wasson, Greg Waters, Thomas Watts, Eugene
|
||||
Weber, David Welch, Martin Whitaker, Marco Widmer, Leon Wildman, Daniel
|
||||
Wilkerson, Gerald Williams, Trevor Williams, Jeff Winston, Joshua Wise,
|
||||
Clifford Wolf, Tobias Wolfel, Johan Wouters, Paul Wright, Junyi Xi, Ding
|
||||
Xiaoliang, Jie Xu, Mandy Xu, Yinan Xu, Luke Yang, Amir Yazdanbakhsh, and
|
||||
Keyi Zhang.
|
||||
Wallentowitz, Shawn Wang, Zhanglei Wang, Paul Wasson, Greg Waters, Thomas
|
||||
Watts, Eugene Weber, David Welch, Thomas J Whatson, Martin Whitaker, Marco
|
||||
Widmer, Leon Wildman, Daniel Wilkerson, Gerald Williams, Trevor Williams,
|
||||
Jeff Winston, Joshua Wise, Clifford Wolf, Tobias Wolfel, Johan Wouters,
|
||||
Paul Wright, Junyi Xi, Ding Xiaoliang, Jie Xu, Mandy Xu, Yinan Xu, Luke
|
||||
Yang, Amir Yazdanbakhsh, Keyi Zhang, and Xi Zhang.
|
||||
|
||||
Thanks to them, and all those we've missed mentioning above, and to those
|
||||
whom have wished to remain anonymous.
|
||||
|
||||
Thanks to them, and all those we've missed including above, or wished to
|
||||
remain anonymous.
|
||||
|
||||
Historical Origins
|
||||
==================
|
||||
|
||||
Verilator was conceived in 1994 by Paul Wasson at the Core Logic Group at
|
||||
Digital Equipment Corporation. The Verilog code that was converted to C
|
||||
was then merged with a C based CPU model of the Alpha processor and
|
||||
simulated in a C based environment called CCLI.
|
||||
was then merged with a C-based CPU model of the Alpha processor and
|
||||
simulated in a C-based environment called CCLI.
|
||||
|
||||
In 1995 Verilator started being used also for Multimedia and Network
|
||||
Processor development inside Digital. Duane Galbi took over active
|
||||
development of Verilator, and added several performance enhancements. CCLI
|
||||
was still being used as the shell.
|
||||
In 1995 Verilator started being used for Multimedia and Network Processor
|
||||
development inside Digital. Duane Galbi took over the active development
|
||||
of Verilator, and added several performance enhancements, and CCLI was
|
||||
still being used as the shell.
|
||||
|
||||
In 1998, through the efforts of existing DECies, mainly Duane Galbi,
|
||||
Digital graciously agreed to release the source code. (Subject to the code
|
||||
not being resold, which is compatible with the GNU Public License.)
|
||||
|
||||
In 2001, Wilson Snyder took the kit, and added a SystemC mode, and called
|
||||
In 2001, Wilson Snyder took the kit, added a SystemC mode, and called
|
||||
it Verilator2. This was the first packaged public release.
|
||||
|
||||
In 2002, Wilson Snyder created Verilator 3.000 by rewriting Verilator from
|
||||
@@ -151,6 +164,10 @@ In 2018, Verilator 4.000 was released with multithreaded support.
|
||||
In 2019, Verilator joined the `CHIPS Alliance
|
||||
<https://chipsalliance.org>`_.
|
||||
|
||||
In 2022, Verilator 5.000 was released with IEEE scheduling semantics,
|
||||
fork/join, delay handling, DFG performance optimizations, and other
|
||||
improvements.
|
||||
|
||||
Currently, various language features and performance enhancements are added
|
||||
as the need arises. Verilator is now about 3x faster than in 2002, and is
|
||||
faster than most (if not every) other simulator.
|
||||
as the need arises, focusing on completing Universal Verification
|
||||
Methodology (UVM, IEEE 1800.2-2017) support.
|
||||
|
||||
@@ -13,7 +13,7 @@ can redistribute it and/or modify the Verilator internals under the terms
|
||||
of either the GNU Lesser General Public License Version 3 or the Perl
|
||||
Artistic License Version 2.0.
|
||||
|
||||
All Verilog and C++/SystemC code quoted within this documentation file are
|
||||
released as Creative Commons Public Domain (CC0). Many example files and
|
||||
All Verilog and C++/SystemC code quoted within this documentation file is
|
||||
released as Creative Commons Public Domain (CC0). Many example files and
|
||||
test files are likewise released under CC0 into effectively the Public
|
||||
Domain as described in the files themselves.
|
||||
|
||||
@@ -7,9 +7,15 @@ Deprecations
|
||||
The following deprecated items are scheduled for future removal:
|
||||
|
||||
C++11 compiler support
|
||||
Verilator currently requires C++11 or newer compilers. Verilator will
|
||||
require C++14 or newer compilers for both compiling Verilator and
|
||||
compiling Verilated models no sooner than January 2023.
|
||||
Verilator currently requires a C++20 or newer compiler for timing, and a
|
||||
C++11 or newer compiler for no-timing.
|
||||
|
||||
Verilator will require C++14 or newer compilers for both compiling
|
||||
Verilator and compiling Verilated models with --no-timing no sooner than
|
||||
January 2023.
|
||||
|
||||
Verilator will require C++20 or newer compilers for both compiling
|
||||
Verilator and compiling all Verilated models no sooner than January 2025.
|
||||
|
||||
Verilated_heavy.h
|
||||
The legacy "verilated_heavy.h" include was replaced with just including
|
||||
|
||||
@@ -10,7 +10,7 @@ associated programs.
|
||||
.. option:: LD_LIBRARY_PATH
|
||||
|
||||
A generic Linux/OS variable specifying what directories have shared
|
||||
object (.so) files. This path should include SystemC and any other
|
||||
object (.so) files. This path should include SystemC and other
|
||||
shared objects needed at simulation runtime.
|
||||
|
||||
.. option:: MAKE
|
||||
@@ -20,6 +20,12 @@ associated programs.
|
||||
this variable to launch GNU make. If this variable is not specified,
|
||||
"make" is used.
|
||||
|
||||
.. option:: MAKEFLAGS
|
||||
|
||||
Flags created by :command:`make` to pass to submakes. Verilator searches
|
||||
this variable to determine if a jobserver is used; see
|
||||
:vlopt:`--build-jobs`.
|
||||
|
||||
.. option:: OBJCACHE
|
||||
|
||||
Optionally specifies a caching or distribution program to place in front
|
||||
@@ -54,14 +60,14 @@ associated programs.
|
||||
|
||||
.. option:: SYSTEMC_INCLUDE
|
||||
|
||||
If set, specifies the directory containing the systemc.h header file. If
|
||||
not specified, it will come from a default optionally specified at
|
||||
If set, specifies the directory containing the systemc.h header file.
|
||||
If not specified, it will come from a default optionally specified at
|
||||
configure time (before Verilator was compiled), or computed from
|
||||
SYSTEMC/include.
|
||||
|
||||
.. option:: SYSTEMC_LIBDIR
|
||||
|
||||
If set, specifies the directory containing the libsystemc.a library. If
|
||||
If set, specifies the directory containing the libsystemc.a library. If
|
||||
not specified, it will come from a default optionally specified at
|
||||
configure time (before Verilator was compiled), or computed from
|
||||
SYSTEMC/lib-SYSTEMC_ARCH.
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
.. Copyright 2003-2022 by Wilson Snyder.
|
||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
.. _Example Create-Binary Execution:
|
||||
|
||||
Example Create-Binary Execution
|
||||
===============================
|
||||
|
||||
We'll compile this SystemVerilog example into a Verilated simulation binary. For
|
||||
an example that discusses the next level of detail see :ref:`Example C++
|
||||
Execution`.
|
||||
|
||||
.. include:: example_common_install.rst
|
||||
|
||||
Now, let's create an example Verilog file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
mkdir test_our
|
||||
cd test_our
|
||||
|
||||
cat >our.v <<'EOF'
|
||||
module our;
|
||||
initial begin $display("Hello World"); $finish; end
|
||||
endmodule
|
||||
EOF
|
||||
|
||||
Now we run Verilator on our little example.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
verilator --binary -j 0 -Wall our.v
|
||||
|
||||
Breaking this command down:
|
||||
|
||||
#. :vlopt:`--binary` telling Verilator to do everything needed to create a
|
||||
simulation executable.
|
||||
|
||||
#. :vlopt:`-j` `0` to Verilate using use as many CPU threads as the machine
|
||||
has.
|
||||
|
||||
#. :vlopt:`-Wall` so Verilator has stronger lint warnings
|
||||
enabled.
|
||||
|
||||
#. An finally, :command:`our.v`, which is our SystemVerilog design file.
|
||||
|
||||
And now we run it:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
obj_dir/Vour
|
||||
|
||||
And we get as output:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
Hello World
|
||||
- our.v:2: Verilog $finish
|
||||
|
||||
You're better off using a Makefile to run the steps for you, so when your
|
||||
source changes, it will automatically run all of the appropriate steps. To
|
||||
aid this, Verilator can create a makefile dependency file. For examples
|
||||
that do this, see the :file:`examples` directory in the distribution.
|
||||
+16
-14
@@ -12,7 +12,7 @@ of what this C++ code is doing, see
|
||||
|
||||
.. include:: example_common_install.rst
|
||||
|
||||
Now, let's create an example Verilog, and C++ wrapper file:
|
||||
Now, let's create an example Verilog and C++ wrapper file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -28,7 +28,7 @@ Now, let's create an example Verilog, and C++ wrapper file:
|
||||
cat >sim_main.cpp <<'EOF'
|
||||
#include "Vour.h"
|
||||
#include "verilated.h"
|
||||
int main(int argc, char** argv, char** env) {
|
||||
int main(int argc, char** argv) {
|
||||
VerilatedContext* contextp = new VerilatedContext;
|
||||
contextp->commandArgs(argc, argv);
|
||||
Vour* top = new Vour{contextp};
|
||||
@@ -39,19 +39,15 @@ Now, let's create an example Verilog, and C++ wrapper file:
|
||||
}
|
||||
EOF
|
||||
|
||||
Now we run Verilator on our little example.
|
||||
Now we run Verilator on our little example;
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
verilator -Wall --cc --exe --build sim_main.cpp our.v
|
||||
verilator --cc --exe --build -j 0 -Wall sim_main.cpp our.v
|
||||
|
||||
Breaking this command down:
|
||||
|
||||
#. :vlopt:`-Wall` so Verilator has stronger lint warnings
|
||||
enabled.
|
||||
|
||||
#. :vlopt:`--cc` to get C++ output (versus e.g. SystemC
|
||||
or only linting).
|
||||
#. :vlopt:`--cc` to get C++ output (versus e.g., SystemC, or only linting).
|
||||
|
||||
#. :vlopt:`--exe`, along with our :command:`sim_main.cpp` wrapper file, so
|
||||
the build will create an executable instead of only a library.
|
||||
@@ -61,7 +57,13 @@ Breaking this command down:
|
||||
own compile rules, and run make yourself as we show in :ref:`Example
|
||||
SystemC Execution`.)
|
||||
|
||||
#. An finally, :command:`our.v` which is our SystemVerilog design file.
|
||||
#. :vlopt:`-j 0 <-j>` to Verilate using use as many CPU threads as the
|
||||
machine has.
|
||||
|
||||
#. :vlopt:`-Wall` so Verilator has stronger lint warnings
|
||||
enabled.
|
||||
|
||||
#. And finally, :command:`our.v` which is our SystemVerilog design file.
|
||||
|
||||
Once Verilator completes we can see the generated C++ code under the
|
||||
:file:`obj_dir` directory.
|
||||
@@ -86,7 +88,7 @@ And we get as output:
|
||||
Hello World
|
||||
- our.v:2: Verilog $finish
|
||||
|
||||
Really, you're better off using a Makefile to run the steps for you so when
|
||||
your source changes it will automatically run all of the appropriate steps.
|
||||
To aid this Verilator can create a makefile dependency file. For examples
|
||||
that do this see the :file:`examples` directory in the distribution.
|
||||
You're better off using a Makefile to run the steps for you, so when your
|
||||
source changes, it will automatically run all of the appropriate steps. To
|
||||
aid this, Verilator can create a makefile dependency file. For examples
|
||||
that do this, see the :file:`examples` directory in the distribution.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
.. Copyright 2003-2022 by Wilson Snyder.
|
||||
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
First you need Verilator installed, see :ref:`Installation`. In brief, if
|
||||
First you need Verilator installed, see :ref:`Installation`. In brief, if
|
||||
you installed Verilator using the package manager of your operating system,
|
||||
or did a :command:`make install` to place Verilator into your default path,
|
||||
you do not need anything special in your environment, and should not have
|
||||
|
||||
@@ -7,9 +7,11 @@ Examples in the Distribution
|
||||
============================
|
||||
|
||||
See the ``examples/`` directory that is part of the distribution, and
|
||||
is installed (in a OS-specific place, often in e.g.
|
||||
is installed (in an OS-specific place, often in e.g.
|
||||
``/usr/local/share/verilator/examples``). These examples include:
|
||||
|
||||
examples/make_hello_binary
|
||||
Example GNU-make simple Verilog->binary conversion
|
||||
examples/make_hello_c
|
||||
Example GNU-make simple Verilog->C++ conversion
|
||||
examples/make_hello_sc
|
||||
|
||||
@@ -43,7 +43,7 @@ Now we run Verilator on our little example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
verilator -Wall --sc --exe sc_main.cpp our.v
|
||||
verilator --sc --exe -Wall sc_main.cpp our.v
|
||||
|
||||
This example does not use --build, therefore we need to explicitly compile
|
||||
it:
|
||||
|
||||
@@ -17,6 +17,7 @@ This section covers the following examples:
|
||||
:maxdepth: 1
|
||||
:hidden:
|
||||
|
||||
example_binary.rst
|
||||
example_cc.rst
|
||||
example_sc.rst
|
||||
example_dist.rst
|
||||
|
||||
@@ -8,7 +8,7 @@ Simulation Runtime Arguments
|
||||
|
||||
The following are the arguments that may be passed to a Verilated
|
||||
executable, provided that executable calls
|
||||
:code:`Verilated::commandArgs()`.
|
||||
:code:`VerilatedContext*->commandArgs(argc, argv)`.
|
||||
|
||||
All simulation runtime arguments begin with "+verilator", so that the
|
||||
user's executable may skip over all "+verilator" arguments when parsing its
|
||||
@@ -72,7 +72,7 @@ Summary:
|
||||
|
||||
.. option:: +verilator+prof+threads+window+<value>
|
||||
|
||||
Deprecated. Alias for :vlopt:`+verilator+prof+exec+window+\<filename\>`
|
||||
Deprecated. Alias for :vlopt:`+verilator+prof+exec+window+\<value\>`
|
||||
|
||||
.. option:: +verilator+prof+vlt+file+<filename>
|
||||
|
||||
@@ -82,10 +82,10 @@ Summary:
|
||||
|
||||
.. option:: +verilator+rand+reset+<value>
|
||||
|
||||
When a model was Verilated using :vlopt:`--x-initial unique
|
||||
<--x-initial>`, sets the simulation runtime initialization technique. 0
|
||||
= Reset to zeros. 1 = Reset to all-ones. 2 = Randomize. See
|
||||
:ref:`Unknown States`.
|
||||
When a model was Verilated using
|
||||
:vlopt:`--x-initial unique <--x-initial>`, sets the simulation runtime
|
||||
initialization technique. 0 = Reset to zeros. 1 = Reset to all-ones. 2
|
||||
= Randomize. See :ref:`Unknown States`.
|
||||
|
||||
.. option:: +verilator+seed+<value>
|
||||
|
||||
@@ -96,7 +96,7 @@ Summary:
|
||||
.. option:: +verilator+noassert
|
||||
|
||||
Disable assert checking per runtime argument. This is the same as
|
||||
calling :code:`Verilated::assertOn(false)` in the model.
|
||||
calling :code:`VerilatedContext*->assertOn(false)` in the model.
|
||||
|
||||
.. option:: +verilator+V
|
||||
|
||||
|
||||
+559
-379
File diff suppressed because it is too large
Load Diff
@@ -12,8 +12,8 @@ coverage points exist on the same source code line, additional lines will
|
||||
be inserted to report the additional points.
|
||||
|
||||
Additional Verilog-XL-style standard arguments specify the search paths
|
||||
necessary to find the source code that the coverage analysis was performed
|
||||
on.
|
||||
necessary to find the source code on which the coverage analysis was
|
||||
performed.
|
||||
|
||||
To filter those items to be included in coverage, you may read
|
||||
logs/coverage.dat into an editor and do a M-x keep-lines to include only
|
||||
@@ -24,7 +24,7 @@ statement to the appropriate statement block, or see
|
||||
:option:`/*verilator&32;coverage_off*/`. This will remove the coverage
|
||||
points after the model is re-Verilated.
|
||||
|
||||
For an overview of use of verilator_coverage, see :ref:`Coverage Analysis`.
|
||||
For an overview of the use of verilator_coverage, see :ref:`Coverage Analysis`.
|
||||
|
||||
|
||||
verilator_coverage Example Usage
|
||||
@@ -50,25 +50,25 @@ verilator_coverage Arguments
|
||||
.. option:: <filename>
|
||||
|
||||
Specifies the input coverage data file. Multiple filenames may be provided
|
||||
to read multiple inputs. If no data file is specified, by default
|
||||
to read multiple inputs. If no data file is specified, by default,
|
||||
"coverage.dat" will be read.
|
||||
|
||||
.. option:: --annotate <output_directory>
|
||||
|
||||
Specifies the directory name that source files with annotated coverage data
|
||||
should be written to.
|
||||
Specifies the directory name to which source files with annotated coverage
|
||||
data should be written.
|
||||
|
||||
.. option:: --annotate-all
|
||||
|
||||
Specifies all files should be shown. By default, only those source files
|
||||
which have low coverage are written to the output directory.
|
||||
with low coverage are written to the output directory.
|
||||
|
||||
.. option:: --annotate-min <count>
|
||||
|
||||
Specifies if the coverage point does not include the count number of
|
||||
coverage hits, then the coverage point will be considered above the
|
||||
threshold, and the coverage report will put a "%" to indicate the coverage
|
||||
is not sufficient. Defaults to 10.
|
||||
is insufficient. Defaults to 10.
|
||||
|
||||
.. option:: --help
|
||||
|
||||
@@ -78,12 +78,12 @@ Displays a help summary, the program version, and exits.
|
||||
|
||||
Prints an experimental report listing the relative importance of each test
|
||||
in covering all of the coverage points. The report shows "Covered" which
|
||||
indicates the number of points that test covers; a test is considered to
|
||||
indicates the number of points the test covers; a test is considered to
|
||||
cover a point if it has a bucket count of at least 1. The "rank" column has
|
||||
a higher number t indicate the test is more important, and rank 0 means the
|
||||
a higher number t indicate the test is more critical, and rank 0 means the
|
||||
test does not need to be run to cover the points. "RankPts" indicates the
|
||||
number of coverage points this test will contribute to overall coverage if
|
||||
all tests are run in the order of highest to lowest rank.
|
||||
all tests are run in the order of highest to the lowest rank.
|
||||
|
||||
.. option:: --unlink
|
||||
|
||||
@@ -98,8 +98,8 @@ Displays program version and exits.
|
||||
|
||||
Specifies the aggregate coverage results, summed across all the files,
|
||||
should be written to the given filename in verilator_coverage data format.
|
||||
This is useful for use in scripts to combine many coverage data files
|
||||
(likely generated from random test runs) into one master coverage file.
|
||||
This is useful in scripts to combine many coverage data files (likely
|
||||
generated from random test runs) into one master coverage file.
|
||||
|
||||
.. option:: --write-info <filename.info>
|
||||
|
||||
@@ -108,7 +108,8 @@ should be written to the given filename in :command:`lcov` .info format.
|
||||
This may be used to feed into :command:`lcov` to aggregate or generate
|
||||
reports.
|
||||
|
||||
The info format loses data compared to the Verilator coverage data format;
|
||||
the info will all forms of coverage converted to line style coverage, and
|
||||
if there are multiple coverage points on a single line, the minimum
|
||||
coverage across those points will be used to report coverage of the line.
|
||||
Converting from the Verilator coverage data format to the info format is
|
||||
lossy; the info will have all forms of coverage merged line coverage, and
|
||||
if there are multiple coverage points on a single line they will merge.
|
||||
The minimum coverage across all merged points will be used to report
|
||||
coverage of the line.
|
||||
|
||||
@@ -5,16 +5,16 @@ verilator_gantt
|
||||
===============
|
||||
|
||||
Verilator_gantt creates a visual representation to help analyze Verilator
|
||||
multithreaded simulation performance, by showing when each macro-task
|
||||
starts and ends, and showing when each thread is busy or idle.
|
||||
multithreaded simulation performance by showing when each macro-task
|
||||
starts, ends, and when each thread is busy or idle.
|
||||
|
||||
For an overview of use of verilator_gantt, see :ref:`Profiling`.
|
||||
For an overview of the use of verilator_gantt, see :ref:`Profiling`.
|
||||
|
||||
Gantt Chart VCD
|
||||
---------------
|
||||
|
||||
Verilated_gantt creates a value change dump (VCD) format dump file which
|
||||
may be viewed in a waveform viewer (e.g. C<GTKWave>):
|
||||
may be viewed in a waveform viewer (e.g., C<GTKWave>):
|
||||
|
||||
.. figure:: figures/fig_gantt_min.png
|
||||
|
||||
@@ -27,9 +27,8 @@ time tick of the system's high-performance counter.
|
||||
Gantt Chart VCD Signals
|
||||
-----------------------
|
||||
|
||||
In waveforms there are the following signals. In GTKWave, using a data
|
||||
format of "decimal" will remove the leading zeros and make the traces
|
||||
easier to read.
|
||||
In waveforms, there are the following signals. In GTKWave, use "decimal"
|
||||
data format to remove the leading zeros and make the traces easier to read.
|
||||
|
||||
evals
|
||||
Increments each time when eval_step was measured to be active. This
|
||||
@@ -37,12 +36,12 @@ evals
|
||||
|
||||
eval_loop
|
||||
Increments each time when the evaluation loop within eval_step was
|
||||
measured to be active. For best performance there is only a single
|
||||
evaluation loop within each eval_step call, that is the eval_loop
|
||||
measured to be active. For best performance, there is only a single
|
||||
evaluation loop within each eval_step call; that is, the eval_loop
|
||||
waveform looks identical to the evals waveform.
|
||||
|
||||
measured_parallelism
|
||||
The number of mtasks active at this time, for best performance this will
|
||||
The number of mtasks active at this time, for best performance, this will
|
||||
match the thread count. In GTKWave, use a data format of "analog step" to
|
||||
view this signal.
|
||||
|
||||
@@ -72,7 +71,7 @@ verilator_gantt Arguments
|
||||
|
||||
.. option:: <filename>
|
||||
|
||||
The filename to read data from, defaults to "profile_exec.dat".
|
||||
The filename to read data from; the default is "profile_exec.dat".
|
||||
|
||||
.. option:: --help
|
||||
|
||||
@@ -84,4 +83,4 @@ Disables creating a .vcd file.
|
||||
|
||||
.. option:: --vcd <filename>
|
||||
|
||||
Sets the output filename for vcd dump. Default is "verilator_gantt.vcd".
|
||||
Sets the output filename for vcd dump; the default is "verilator_gantt.vcd".
|
||||
|
||||
@@ -6,14 +6,14 @@ verilator_profcfunc
|
||||
|
||||
Verilator_profcfunc reads a profile report created by gprof. The names of
|
||||
the functions are then transformed, assuming the user used Verilator's
|
||||
--prof-cfuncs, and a report printed showing the percentage of time, etc, in
|
||||
each Verilog block.
|
||||
--prof-cfuncs, and a report printed showing the percentage of the time,
|
||||
etc., in each Verilog block.
|
||||
|
||||
Due to rounding errors in gprof reports, the input report's percentages may
|
||||
not total to 100%. In the verilator_profcfunc report this will get
|
||||
not total 100%. In the verilator_profcfunc report this will get
|
||||
reported as a rounding error.
|
||||
|
||||
For an overview of use of verilator_profcfunc, see :ref:`Profiling`.
|
||||
For an overview of the use of verilator_profcfunc, see :ref:`Profiling`.
|
||||
|
||||
verilator_profcfunc Arguments
|
||||
-----------------------------
|
||||
|
||||
+123
-76
@@ -12,19 +12,25 @@ or "`ifdef`"'s may break other tools.
|
||||
.. option:: `__FILE__
|
||||
|
||||
The :option:`\`__FILE__` define expands to the current filename as a
|
||||
string, like C++'s __FILE__. This Verilator feature added in 2006 was
|
||||
incorporated into the IEEE 1800-2009 standard.
|
||||
string, like C++'s __FILE__. This Verilator feature, added in 2006, was
|
||||
incorporated into IEEE 1800-2009.
|
||||
|
||||
.. option:: `__LINE__
|
||||
|
||||
The :option:`\`__LINE__` define expands to the current filename as a
|
||||
string, like C++'s __LINE__. This Verilator feature added in 2006 was
|
||||
incorporated into the IEEE 1800-2009 standard.
|
||||
incorporated into IEEE 1800-2009.
|
||||
|
||||
.. option:: `error [string]
|
||||
|
||||
This will report an error when encountered, like C++'s #error.
|
||||
|
||||
.. option:: """ [string] """
|
||||
|
||||
A triple-quoted block specifies a string that may include newlines and
|
||||
single quotes. This extension is experimental and may be removed
|
||||
without deprecation.
|
||||
|
||||
.. option:: $c([string], ...);
|
||||
|
||||
The string will be embedded directly in the output C++ code at the point
|
||||
@@ -45,24 +51,24 @@ or "`ifdef`"'s may break other tools.
|
||||
rather than hard-coding variable names in the string
|
||||
:code:`$c("func(a)")`, instead pass the variable as an expression
|
||||
::code:`$c("func(",a,")")`. This will allow the call to work inside
|
||||
Verilog functions where the variable is flattened out, and also enable
|
||||
other optimizations.
|
||||
Verilog functions where the variable is flattened out and enable other
|
||||
optimizations.
|
||||
|
||||
Verilator does not use any text inside the quotes for
|
||||
ordering/scheduling. If you need the $c to be called at a specific
|
||||
time, e.g. when a variable changes, then the $c must be under an
|
||||
appropriate sensitivity statement, e.g. :code:`always @(posedge clk)
|
||||
$c("func()")` to call it on every edge, or e.g. :code:`always @*
|
||||
c("func(",a,")")` to call it when :code:`a` changes (the latter working
|
||||
because :code:`a` is outside the quotes).
|
||||
time, e.g., when a variable changes, then the $c must be under an
|
||||
appropriate sensitivity statement, e.g.,
|
||||
:code:`always @(posedge clk) $c("func()")` to call it on every edge, or,
|
||||
e.g., :code:`always @* c("func(",a,")")` to call it when :code:`a`
|
||||
changes (the latter working because :code:`a` is outside the quotes).
|
||||
|
||||
If you will be reading or writing any Verilog variables inside the C++
|
||||
functions, the Verilog signals must be declared with
|
||||
:option:`/*verilator&32;public*/` metacomments.
|
||||
|
||||
You may also append an arbitrary number to $c, generally the width of
|
||||
the output; :code:`signal_32_bits = $c32("...");`. This allows for
|
||||
compatibility with other simulators which require a differently named
|
||||
You may also append a number to $c, which specifies the bit width of
|
||||
the output, e.g., :code:`signal_32_bits = $c32("...");`. This allows for
|
||||
compatibility with other simulators, which require a differently named
|
||||
PLI function name for each different output width.
|
||||
|
||||
.. option:: $display, $write, $fdisplay, $fwrite, $sformat, $swrite
|
||||
@@ -70,61 +76,71 @@ or "`ifdef`"'s may break other tools.
|
||||
Format arguments may use C fprintf sizes after the % escape. Per the
|
||||
Verilog standard, %x prints a number with the natural width, and %0x
|
||||
prints a number with minimum width. Verilator extends this so %5x
|
||||
prints 5 digits per the C standard (this is unspecified in Verilog, but
|
||||
was incorporated into the 1800-2009).
|
||||
prints 5 digits per the C standard. This extension was standardized into
|
||||
1800-2009.
|
||||
|
||||
.. option:: $timeprecision
|
||||
|
||||
Returns the timeprecision of the model as an integer. This extension is
|
||||
experimental and may be removed without deprecation.
|
||||
|
||||
.. option:: $timeunit
|
||||
|
||||
Returns the timeunit of the current module as an integer. This
|
||||
extension is experimental and may be removed without deprecation.
|
||||
|
||||
.. option:: `coverage_block_off
|
||||
|
||||
Specifies the entire begin/end block should be ignored for coverage
|
||||
analysis. Must be inside a code block, e.g. within a begin/end pair.
|
||||
analysis. Must be inside a code block, e.g., within a begin/end pair.
|
||||
Same as :option:`coverage_block_off` in :ref:`Configuration Files`.
|
||||
|
||||
.. option:: `systemc_header
|
||||
|
||||
Take remaining text up to the next :option:`\`verilog` or
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the output .h file's header. Must be placed as a module
|
||||
item, e.g. directly inside a module/endmodule pair. Despite the name of
|
||||
item, e.g., directly inside a module/endmodule pair. Despite the name of
|
||||
this macro, this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_ctor
|
||||
|
||||
Take remaining text up to the next :option:`\`verilog` or
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the C++ class constructor. Must be placed as a module
|
||||
item, e.g. directly inside a module/endmodule pair. Despite the name of
|
||||
item, e.g., directly inside a module/endmodule pair. Despite the name of
|
||||
this macro, this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_dtor
|
||||
|
||||
Take remaining text up to the next :option:`\`verilog` or
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the C++ class destructor. Must be placed as a module
|
||||
item, e.g. directly inside a module/endmodule pair. Despite the name of
|
||||
item, e.g., directly inside a module/endmodule pair. Despite the name of
|
||||
this macro, this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_interface
|
||||
|
||||
Take remaining text up to the next :option:`\`verilog` or
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the C++ class interface. Must be placed as a module item,
|
||||
e.g. directly inside a module/endmodule pair. Despite the name of this
|
||||
e.g., directly inside a module/endmodule pair. Despite the name of this
|
||||
macro, this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_imp_header
|
||||
|
||||
Take remaining text up to the next :option:`\`verilog` or
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into the header of all files for this C++ class implementation.
|
||||
Must be placed as a module item, e.g. directly inside a module/endmodule
|
||||
Must be placed as a module item, e.g., directly inside a module/endmodule
|
||||
pair. Despite the name of this macro, this also works in pure C++ code.
|
||||
|
||||
.. option:: `systemc_implementation
|
||||
|
||||
Take remaining text up to the next :option:`\`verilog` or
|
||||
Take the remaining text up to the next :option:`\`verilog` or
|
||||
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
|
||||
verbatim into a single file of the C++ class implementation. Must be
|
||||
placed as a module item, e.g. directly inside a module/endmodule
|
||||
placed as a module item, e.g., directly inside a module/endmodule
|
||||
pair. Despite the name of this macro, this also works in pure C++ code.
|
||||
|
||||
If you will be reading or writing any Verilog variables in the C++
|
||||
@@ -134,7 +150,7 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
.. option:: `SYSTEMVERILOG
|
||||
|
||||
The SYSTEMVERILOG, SV_COV_START and related standard defines are set by
|
||||
The SYSTEMVERILOG, SV_COV_START, and related standard defines are set by
|
||||
default when :vlopt:`--language <--language>` is "1800-\*".
|
||||
|
||||
.. option:: `VERILATOR
|
||||
@@ -148,9 +164,16 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
.. option:: `verilator_config
|
||||
|
||||
Take remaining text up to the next :option:`\`verilog` mode switch and
|
||||
Take the remaining text up to the next :option:`\`verilog` mode switch and
|
||||
treat it as Verilator configuration commands. See :ref:`Configuration Files`.
|
||||
|
||||
.. option:: `VERILATOR_TIMING
|
||||
|
||||
The VERILATOR_TIMING define is set when :vlopt:`--timing` is used to
|
||||
allow an "\`ifdef" of code dependent on this feature. Note that this define
|
||||
is not affected by the :option:`timing_off` configuration file option
|
||||
nor timing metacomments.
|
||||
|
||||
.. option:: `verilog
|
||||
|
||||
Switch back to processing Verilog code after a
|
||||
@@ -160,8 +183,12 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
.. option:: /*verilator&32;clock_enable*/
|
||||
|
||||
Deprecated and has no effect (ignored).
|
||||
|
||||
In versions before 5.000:
|
||||
|
||||
Used after a signal declaration to indicate the signal is used to gate a
|
||||
clock, and the user takes responsibility for insuring there are no races
|
||||
clock, and the user is responsible for ensuring there are no races
|
||||
related to it. (Typically by adding a latch, and running static timing
|
||||
analysis.) For example:
|
||||
|
||||
@@ -174,9 +201,7 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
The clock_enable attribute will cause the clock gate to be ignored in
|
||||
the scheduling algorithm, sometimes required for correct clock behavior,
|
||||
and always improving performance. It's also a good idea to enable the
|
||||
:option:`IMPERFECTSCH` warning, to ensure all clock enables are properly
|
||||
recognized.
|
||||
and always improving performance.
|
||||
|
||||
Same as :option:`clock_enable` configuration file option.
|
||||
|
||||
@@ -184,9 +209,7 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
.. option:: /*verilator&32;no_clocker*/
|
||||
|
||||
Specifies that the signal is used as clock or not. This information is
|
||||
used by Verilator to mark the signal and any derived signals as
|
||||
clocker. See :vlopt:`--clk`.
|
||||
Specifies whether the signal is used as clock or not. See :vlopt:`--clk`.
|
||||
|
||||
Same as :option:`clocker` and :option:`no_clocker` in configuration
|
||||
files.
|
||||
@@ -200,12 +223,12 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
.. option:: /*verilator&32;coverage_off*/
|
||||
|
||||
Specifies that following lines of code should have coverage disabled.
|
||||
Specifies that that following lines of code should have coverage disabled.
|
||||
Often used to ignore an entire module for coverage analysis purposes.
|
||||
|
||||
.. option:: /*verilator&32;coverage_on*/
|
||||
|
||||
Specifies that following lines of code should have coverage re-enabled
|
||||
Specifies that that following lines of code should have coverage re-enabled
|
||||
(if appropriate :vlopt:`--coverage` flags are passed) after being
|
||||
disabled earlier with :option:`/*verilator&32;coverage_off*/`.
|
||||
|
||||
@@ -213,7 +236,7 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
Specifies that the signal (net or variable) should be made forceable from
|
||||
C++ code by generating public `<signame>__VforceEn` and
|
||||
`<signame>__VforceVal` signals The force control signals are created as
|
||||
`<signame>__VforceVal` signals. The force control signals are created as
|
||||
:option:`public_flat` signals.
|
||||
|
||||
To force a marked signal from C++, set the corresponding `__VforceVal`
|
||||
@@ -249,10 +272,10 @@ or "`ifdef`"'s may break other tools.
|
||||
.. option:: /*verilator&32;isolate_assignments*/
|
||||
|
||||
Used after a signal declaration to indicate the assignments to this
|
||||
signal in any blocks should be isolated into new blocks. When there is
|
||||
a large combinatorial block that is resulting in an ``UNOPTFLAT``
|
||||
warning, attaching this to the signal causing a false loop may clear up
|
||||
the problem.
|
||||
signal in any blocks should be isolated into new blocks. When large
|
||||
combinatorial block results in a :option:`UNOPTFLAT` warning, attaching
|
||||
this to the signal that was causing a false loop may work around the
|
||||
warning.
|
||||
|
||||
IE, with the following:
|
||||
|
||||
@@ -306,7 +329,7 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
.. option:: /*verilator&32;lint_save*/
|
||||
|
||||
Push the current state of what lint messages are turned on or turned off
|
||||
Push the current state of what lint messages are turned on or off
|
||||
to a stack. Later meta-comments may then lint_on or lint_off specific
|
||||
messages, then return to the earlier message state by using
|
||||
:code:`/*verilator&32;lint_restore*/`. For example:
|
||||
@@ -318,8 +341,8 @@ or "`ifdef`"'s may break other tools.
|
||||
... // code needing WIDTH turned off
|
||||
// verilator lint_restore
|
||||
|
||||
If WIDTH was on before the lint_off, it will now be restored to on, and
|
||||
if it was off before the lint_off it will remain off.
|
||||
If WIDTH was on before the lint_off, it would now be restored to on, and
|
||||
if it was off before the lint_off it would remain off.
|
||||
|
||||
.. option:: /*verilator&32;no_inline_module*/
|
||||
|
||||
@@ -363,13 +386,12 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
Used after an input, output, register, or wire declaration to indicate
|
||||
the signal should be declared so that C code may read or write the value
|
||||
of the signal. This will also declare this module public, otherwise use
|
||||
of the signal. This will also declare this module public; otherwise, use
|
||||
:code:`/*verilator&32;public_flat*/`.
|
||||
|
||||
Instead of using public variables, consider instead making a DPI or
|
||||
public function that accesses the variable. This is nicer as it
|
||||
provides an obvious entry point that is also compatible across
|
||||
simulators.
|
||||
Instead of using public variables, consider making a DPI or public
|
||||
function that accesses the variable. This is nicer as it provides an
|
||||
obvious entry point compatible across simulators.
|
||||
|
||||
Same as :option:`public` configuration file option.
|
||||
|
||||
@@ -379,7 +401,7 @@ or "`ifdef`"'s may break other tools.
|
||||
indicate the function or task should be made into a C++ function, public
|
||||
to outside callers. Public tasks will be declared as a void C++
|
||||
function, public functions will get the appropriate non-void (bool,
|
||||
uint32_t, etc) return type. Any input arguments will become C++
|
||||
uint32_t, etc.) return type. Any input arguments will become C++
|
||||
arguments to the function. Any output arguments will become C++
|
||||
reference arguments. Any local registers/integers will become function
|
||||
automatic variables on the stack.
|
||||
@@ -417,10 +439,10 @@ or "`ifdef`"'s may break other tools.
|
||||
.. option:: /*verilator&32;public_flat_rw @(<edge_list>)*/ (on variable)
|
||||
|
||||
Used after an input, output, register, or wire declaration to indicate
|
||||
the signal should be declared public_flat_rd (see above), and also
|
||||
writable, where writes should be considered to have the timing specified
|
||||
by the given sensitivity edge list. Set for all variables, ports and
|
||||
wires using the :vlopt:`--public-flat-rw` option.
|
||||
the signal should be declared public_flat_rd (see above), and writable,
|
||||
where writes should be considered to have the timing specified by the
|
||||
given sensitivity edge list. Use of this is implied when using the
|
||||
:vlopt:`--public-flat-rw` option.
|
||||
|
||||
Same as :option:`public_flat_rw` configuration file option.
|
||||
|
||||
@@ -429,8 +451,8 @@ or "`ifdef`"'s may break other tools.
|
||||
Used after a module statement to indicate the module should not be
|
||||
inlined (unless specifically requested) so that C code may access the
|
||||
module. Verilator automatically sets this attribute when the module
|
||||
contains any public signals or \`systemc_ directives. Also set for all
|
||||
modules when using the :vlopt:`--public` option.
|
||||
contains public signals or \`systemc_ directives. Use of this is
|
||||
implied when using the :vlopt:`--public` option.
|
||||
|
||||
Same as :option:`public` configuration file option.
|
||||
|
||||
@@ -439,27 +461,26 @@ or "`ifdef`"'s may break other tools.
|
||||
Deprecated and ignored. Previously used after an input declaration to
|
||||
indicate the signal should be declared in SystemC as a sc_clock instead
|
||||
of a bool. This was needed in SystemC 1.1 and 1.2 only; versions 2.0
|
||||
and later do not require clock pins to be sc_clocks and this is no
|
||||
and later do not require clock pins to be sc_clocks, and this is no
|
||||
longer needed and is ignored.
|
||||
|
||||
.. option:: /*verilator&32;sc_bv*/
|
||||
|
||||
Used after a port declaration. It sets the port to be of
|
||||
:code:`sc_bv<{width}>` type, instead of bool, uint32_t or uint64_t.
|
||||
:code:`sc_bv<{width}>` type, instead of bool, uint32_t, or uint64_t.
|
||||
This may be useful if the port width is parameterized and the
|
||||
instantiating C++ code wants to always have a sc_bv so it can accept any
|
||||
width. In general you should avoid using this attribute when not
|
||||
necessary as with increasing usage of sc_bv the performance decreases
|
||||
significantly.
|
||||
instantiating C++ code always wants to have a sc_bv accept any width.
|
||||
In general, you should avoid using this attribute when unnecessary, as
|
||||
the performance decreases significantly with increasing usage of sc_bv.
|
||||
|
||||
Same as :option:`sc_bv` configuration file option.
|
||||
|
||||
.. option:: /*verilator&32;sformat*/
|
||||
|
||||
Attached to the final argument of type "input string" of a function or
|
||||
task to indicate the function or task should pass all remaining
|
||||
task to indicate that the function or task should pass all remaining
|
||||
arguments through $sformatf. This allows creation of DPI functions with
|
||||
$display like behavior. See the :file:`test_regress/t/t_dpi_display.v`
|
||||
$display-like behavior. See the :file:`test_regress/t/t_dpi_display.v`
|
||||
file for an example.
|
||||
|
||||
Same as :option:`sformat` configuration file option.
|
||||
@@ -469,7 +490,7 @@ or "`ifdef`"'s may break other tools.
|
||||
Attached to a variable or a net declaration to break the variable into
|
||||
multiple pieces typically to resolve ``UNOPTFLAT`` performance issues.
|
||||
Typically the variables to attach this to are recommended by Verilator
|
||||
itself, see :option:`UNOPTFLAT`.
|
||||
itself; see :option:`UNOPTFLAT`.
|
||||
|
||||
For example, Verilator will internally convert a variable with the
|
||||
metacomment such as:
|
||||
@@ -486,12 +507,12 @@ or "`ifdef`"'s may break other tools.
|
||||
logic [7:0] x__BRA__1__KET__ /*verilator split_var*/;
|
||||
|
||||
Note that the generated packed variables retain the split_var
|
||||
metacomment because they may be split into further smaller pieces
|
||||
according to the access patterns.
|
||||
metacomment because they may be split into smaller pieces according to
|
||||
the access patterns.
|
||||
|
||||
This only supports unpacked arrays, packed arrays, and packed structs of
|
||||
integer types (reg, logic, bit, byte, int...); otherwise if a split was
|
||||
requested but cannot occur a SPLITVAR warning is issued. Splitting
|
||||
integer types (reg, logic, bit, byte, int...); otherwise, if a split was
|
||||
requested but cannot occur, a SPLITVAR warning is issued. Splitting
|
||||
large arrays may slow down the Verilation speed, so use this only on
|
||||
variables that require it.
|
||||
|
||||
@@ -503,6 +524,22 @@ or "`ifdef`"'s may break other tools.
|
||||
Verilator) text that should be passed through to the XML output as a tag,
|
||||
for use by downstream applications.
|
||||
|
||||
.. option:: /*verilator&32;timing_off*/
|
||||
|
||||
Ignore all timing constructs after this metacomment. All timing controls
|
||||
behave as if they were not there (the same way as with
|
||||
:option:`--no-timing`), and :code:`fork`/:code:`join*` blocks are
|
||||
converted into :code:`begin`/:code:`end` blocks.
|
||||
|
||||
Same as :option:`timing_off` configuration file option.
|
||||
|
||||
.. option:: /*verilator&32;timing_on*/
|
||||
|
||||
Re-enable all timing constructs after this metacomment (only applicable
|
||||
after :option:`timing_off`).
|
||||
|
||||
Same as :option:`timing_on` configuration file option.
|
||||
|
||||
.. option:: /*verilator&32;trace_init_task*/
|
||||
|
||||
Attached to a DPI import to indicate that function should be called when
|
||||
@@ -512,12 +549,22 @@ or "`ifdef`"'s may break other tools.
|
||||
|
||||
.. option:: /*verilator&32;tracing_off*/
|
||||
|
||||
Disable waveform tracing for all future signals that are declared in
|
||||
this module, or instances below this module. Often this is placed just
|
||||
after a primitive's module statement, so that the entire module and
|
||||
instances below it are not traced.
|
||||
Disable waveform tracing for all future signals declared in this module,
|
||||
or instances below this module. Often this is placed just after a
|
||||
primitive's module statement, so that the entire module and instances
|
||||
below it are not traced.
|
||||
|
||||
.. option:: /*verilator&32;tracing_on*/
|
||||
|
||||
Re-enable waveform tracing for all future signals or instances that are
|
||||
declared.
|
||||
|
||||
.. option:: $stacktrace
|
||||
|
||||
Called as a task, print a stack trace. Called as a function, return a
|
||||
string with a stack trace. This relies on the C++ system trace, which
|
||||
may give less meaningful results if the model is not compiled with debug
|
||||
symbols. Also, the data represents the C++ stack; the SystemVerilog
|
||||
functions/tasks involved may be renamed and/or inlined before becoming
|
||||
the C++ functions that may be visible in the stack trace. This
|
||||
extension is experimental and may be removed without deprecation.
|
||||
|
||||
+80
-80
@@ -14,8 +14,8 @@ Can I contribute?
|
||||
"""""""""""""""""
|
||||
|
||||
Please contribute! Just submit a pull request, or raise an issue to
|
||||
discuss if looking for something to help on. For more information see our
|
||||
contributor agreement.
|
||||
discuss if you are looking for something to help on. For more information
|
||||
see our contributor agreement.
|
||||
|
||||
|
||||
How widely is Verilator used?
|
||||
@@ -24,7 +24,7 @@ How widely is Verilator used?
|
||||
Verilator is used by many of the largest silicon design companies, large
|
||||
organizations such as CERN, and even by college student projects.
|
||||
|
||||
Verilator is one of the "big 4" simulators, meaning one of the 4 main
|
||||
Verilator is one of the "big 4" simulators, meaning one of the four leading
|
||||
SystemVerilog simulators available, namely the closed-source products Synopsys
|
||||
VCS (tm), Mentor Questa/ModelSim (tm), Cadence
|
||||
Xcelium/Incisive/NC-Verilog/NC-Sim (tm), and the open-source Verilator.
|
||||
@@ -35,8 +35,8 @@ simulators.
|
||||
Does Verilator run under Windows?
|
||||
"""""""""""""""""""""""""""""""""
|
||||
|
||||
Yes, ideally run Ubuntu under Windows Subsystem for Linux (WSL2).
|
||||
Alternatively use Cygwin, though this tends to be slower and is not
|
||||
Yes, ideally, run Ubuntu under Windows Subsystem for Linux (WSL2).
|
||||
Alternatively, use Cygwin, though this tends to be slower and is not
|
||||
regularly tested. Verilated output also compiles under Microsoft Visual
|
||||
C++, but this is also not regularly tested.
|
||||
|
||||
@@ -58,14 +58,14 @@ How can it be faster than (name-a-big-3-closed-source-simulator)?
|
||||
Generally, the implied part of the question is "... with all of the
|
||||
manpower they can put into developing it."
|
||||
|
||||
Most simulators have to be compliant with the complete IEEE 1364 (Verilog)
|
||||
and IEEE 1800 (SystemVerilog) standards, meaning they have to be event
|
||||
driven. This prevents them from being able to reorder blocks and make
|
||||
netlist-style optimizations, which are where most of the gains come from.
|
||||
Most simulators must comply with the complete IEEE 1364 (Verilog) and IEEE
|
||||
1800 (SystemVerilog) standards, meaning they have to be event-driven. This
|
||||
prevents them from being able to reorder blocks and make netlist-style
|
||||
optimizations, which are where most of the gains come from.
|
||||
|
||||
You should not be scared by non-compliance. Your synthesis tool isn't
|
||||
compliant with the whole standard to start with, so your simulator need not
|
||||
be either. Verilator is closer to the synthesis interpretation, so this is
|
||||
be either. Verilator is closer to the synthesis interpretation, which is
|
||||
a good thing for getting working silicon.
|
||||
|
||||
|
||||
@@ -81,17 +81,17 @@ the licenses for details.
|
||||
|
||||
Some examples:
|
||||
|
||||
* Any SystemVerilog or other input fed into Verilator remain your own.
|
||||
* Any SystemVerilog or other input fed into Verilator remains your own.
|
||||
|
||||
* Any of your VPI/DPI C++ routines that Verilator calls remain your own.
|
||||
|
||||
* Any of your main() C++ code that calls into Verilator remain your own.
|
||||
* Any of your main() C++ code that calls into Verilator remains your own.
|
||||
|
||||
* If you change Verilator itself, for example changing or adding a file
|
||||
* If you change Verilator itself, for example, changing or adding a file
|
||||
under the src/ directory in the repository, you must make the source code
|
||||
available under the GNU Lesser Public License.
|
||||
|
||||
* If you change a header Verilator provides, for example under include/ in
|
||||
* If you change a header Verilator provides, for example, under include/ in
|
||||
the repository, you must make the source code available under the GNU
|
||||
Lesser Public License.
|
||||
|
||||
@@ -101,9 +101,9 @@ license also allows you to modify Verilator for internal use without
|
||||
distributing the modified version. But please contribute back to the
|
||||
community!
|
||||
|
||||
Under both license you can offer a commercial product that is based on
|
||||
Verilator either directly or embedded within. However under both licenses,
|
||||
any changes you make to Verilator for such a product must be open sourced.
|
||||
Under both licenses, you can offer a commercial product based on
|
||||
Verilator directly or embedded within. However, under both licenses,
|
||||
any changes you make to Verilator for such a product must be open-sourced.
|
||||
|
||||
As is standard with Open Source, contributions back to Verilator will be
|
||||
placed under the Verilator copyright and LGPL/Artistic license. Small test
|
||||
@@ -114,11 +114,11 @@ and large tests under the LGPL/Artistic, unless requested otherwise.
|
||||
Why is running Verilator (to create a model) so slow?
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Verilator may require more memory than the resulting simulator will
|
||||
require, as Verilator internally creates all of the state of the resulting
|
||||
generated simulator in order to optimize it. If it takes more than a few
|
||||
Verilator may require more memory than the resulting simulation,
|
||||
as Verilator internally creates all of the state of the resulting
|
||||
generated simulator to optimize it. If it takes more than a few
|
||||
minutes or so (and you're not using :vlopt:`--debug` since debug mode is
|
||||
disk bound), see if your machine is paging; most likely you need to run it
|
||||
disk bound), see if your machine is paging; most likely, you need to run it
|
||||
on a machine with more memory. Very large designs are known to have topped
|
||||
64 GB resident set size. Alternatively, see :ref:`Hierarchical Verilation`.
|
||||
|
||||
@@ -128,14 +128,14 @@ How do I generate waveforms (traces) in C++?
|
||||
|
||||
See also the next question for tracing in SystemC mode.
|
||||
|
||||
A. Pass the :vlopt:`--trace` option to Verilator, and in your top level C
|
||||
A. Pass the :vlopt:`--trace` option to Verilator, and in your top-level C
|
||||
code, call ``Verilated::traceEverOn(true)``. Then you may use
|
||||
``$dumpfile`` and ``$dumpvars`` to enable traces, same as with any
|
||||
``$dumpfile`` and ``$dumpvars`` to enable traces, the same as with any
|
||||
Verilog simulator. See ``examples/make_tracing_c`` in the distribution.
|
||||
|
||||
B. Or, for finer-grained control, or C++ files with multiple Verilated
|
||||
modules you may also create the trace purely from C++. Create a
|
||||
VerilatedVcdC object, and in your main loop right after ``eval()`` call
|
||||
modules, you may also create the trace purely from C++. Create a
|
||||
VerilatedVcdC object, and in your main loop, right after ``eval()`` call
|
||||
``trace_object->dump(contextp->time())`` every time step, and finally
|
||||
call ``trace_object->close()``.
|
||||
|
||||
@@ -144,7 +144,7 @@ B. Or, for finer-grained control, or C++ files with multiple Verilated
|
||||
|
||||
#include "verilated_vcd_c.h"
|
||||
...
|
||||
int main(int argc, char** argv, char** env) {
|
||||
int main(int argc, char** argv) {
|
||||
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
|
||||
...
|
||||
Verilated::traceEverOn(true);
|
||||
@@ -163,8 +163,8 @@ B. Or, for finer-grained control, or C++ files with multiple Verilated
|
||||
|
||||
You also need to compile :file:`verilated_vcd_c.cpp` and add it to your
|
||||
link, preferably by adding the dependencies in your Makefile's
|
||||
:code:`$(VK_GLOBAL_OBJS)` link rule. This is done for you if using the
|
||||
Verilator :vlopt:`--exe` option.
|
||||
:code:`$(VK_GLOBAL_OBJS)` link rule. This is done for you if you are using
|
||||
the Verilator :vlopt:`--binary` or :vlopt:`--exe` option.
|
||||
|
||||
you can call :code:`trace_object->trace()` on multiple Verilated objects
|
||||
with the same trace file if you want all data to land in the same output
|
||||
@@ -174,22 +174,22 @@ file.
|
||||
How do I generate waveforms (traces) in SystemC?
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
A. Pass the :vlopt:`--trace` option to Verilator, and in your top level
|
||||
A. Pass the :vlopt:`--trace` option to Verilator, and in your top-level
|
||||
:code:`sc_main()`, call :code:`Verilated::traceEverOn(true)`. Then you
|
||||
may use :code:`$dumpfile` and code:`$dumpvars` to enable traces, same as
|
||||
with any Verilog simulator, see the non-SystemC example in
|
||||
may use :code:`$dumpfile` and code:`$dumpvars` to enable traces, as
|
||||
with any Verilog simulator; see the non-SystemC example in
|
||||
:file:`examples/make_tracing_c`. This will trace only the module
|
||||
containing the :code:`$dumpvar`.
|
||||
|
||||
B. Or, you may create a trace purely from SystemC, which may trace all
|
||||
Verilated designs in the SystemC model. Create a VerilatedVcdSc object
|
||||
as you would create a normal SystemC trace file. For an example, see
|
||||
as you would create a standard SystemC trace file. For an example, see
|
||||
the call to ``VerilatedVcdSc`` in the
|
||||
:file:`examples/make_tracing_sc/sc_main.cpp` file of the distribution,
|
||||
and below.
|
||||
|
||||
C. Alternatively you may use the C++ trace mechanism described in the
|
||||
previous question, note the timescale and timeprecision will be
|
||||
C. Alternatively, you may use the C++ trace mechanism described in the
|
||||
previous question; note that the timescale and timeprecision will be
|
||||
inherited from your SystemC settings.
|
||||
|
||||
.. code-block:: C++
|
||||
@@ -197,7 +197,7 @@ C. Alternatively you may use the C++ trace mechanism described in the
|
||||
|
||||
#include "verilated_vcd_sc.h"
|
||||
...
|
||||
int main(int argc, char** argv, char** env) {
|
||||
int main(int argc, char** argv) {
|
||||
...
|
||||
Verilated::traceEverOn(true);
|
||||
VerilatedVcdSc* tfp = new VerilatedVcdSc;
|
||||
@@ -214,13 +214,14 @@ C. Alternatively you may use the C++ trace mechanism described in the
|
||||
You also need to compile :file:`verilated_vcd_sc.cpp` and
|
||||
:file:`verilated_vcd_c.cpp` and add them to your link, preferably by adding
|
||||
the dependencies in your Makefile's :code:`$(VK_GLOBAL_OBJS)` link rule.
|
||||
This is done for you if using the Verilator :vlopt:`--exe` option.
|
||||
This is done for you if you are using the Verilator :vlopt:`--binary` or
|
||||
:vlopt:`--exe` option.
|
||||
|
||||
You can call :code:`->trace()` on multiple Verilated objects with the same
|
||||
trace file if you want all data to land in the same output file.
|
||||
|
||||
When using SystemC 2.3, the SystemC library must have been built with the
|
||||
experimental simulation phase callback based tracing disabled. This is
|
||||
experimental simulation phase callback-based tracing disabled. This is
|
||||
disabled by default when building SystemC with its configure based build
|
||||
system, but when building SystemC with CMake, you must pass
|
||||
``-DENABLE_PHASE_CALLBACKS_TRACING=OFF`` to disable this feature.
|
||||
@@ -242,7 +243,7 @@ Or, in C++ change the include described in the VCD example above:
|
||||
VerilatedFstC* tfp = new VerilatedFstC;
|
||||
|
||||
|
||||
Or, in SystemC change the include described in the VCD example above:
|
||||
Or, in SystemC, change the include described in the VCD example above:
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
@@ -250,17 +251,16 @@ Or, in SystemC change the include described in the VCD example above:
|
||||
VerilatedFstC* tfp = new VerilatedFstSc;
|
||||
|
||||
|
||||
Note that currently supporting both FST and VCD in a single simulation is
|
||||
impossible, but such requirement should be rare. You can however ifdef
|
||||
around the trace format in your C++ main loop, and select VCD or FST at
|
||||
build time, should you require.
|
||||
Currently, supporting FST and VCD in a single simulation is impossible, but
|
||||
such requirement should be rare. You can however ifdef around the trace
|
||||
format in your C++ main loop, and select VCD or FST at compile time.
|
||||
|
||||
|
||||
How do I view waveforms (aka dumps or traces)?
|
||||
""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Verilator creates standard VCD (Value Change Dump) and FST files. VCD
|
||||
files are viewable with the open source GTKWave (recommended) or Dinotrace
|
||||
files are viewable with the open-source GTKWave (recommended), or Dinotrace
|
||||
(legacy) programs, or any of the many closed-source offerings; FST is
|
||||
supported only by GTKWave.
|
||||
|
||||
@@ -273,20 +273,20 @@ A. Instead of calling ``VerilatedVcdC->open`` or ``$dumpvars`` at the
|
||||
tracing to begin.
|
||||
|
||||
B. Add the :option:`/*verilator&32;tracing_off*/` metacomment to any very
|
||||
low level modules you never want to trace (such as perhaps library
|
||||
low-level modules you never want to trace (such as perhaps library
|
||||
cells).
|
||||
|
||||
C. Use the :vlopt:`--trace-depth` option to limit the depth of tracing, for
|
||||
example :vlopt:`--trace-depth 1 <--trace-depth>` to see only the top
|
||||
level signals.
|
||||
C. Use the :vlopt:`--trace-depth` option to limit the tracing depth, for
|
||||
example :vlopt:`--trace-depth 1 <--trace-depth>` to see only the
|
||||
top-level signals.
|
||||
|
||||
D. You can also consider using FST tracing instead of VCD. FST dumps are a
|
||||
fraction of the size of the equivalent VCD. FST tracing can be slower
|
||||
than VCD tracing, but it might be the only option if the VCD file size
|
||||
is prohibitively large.
|
||||
|
||||
E. Be sure you write your trace files to a local solid-state drive, instead
|
||||
of to a network drive. Network drives are generally far slower.
|
||||
E. Write your trace files to a machine-local solid-state drive instead of a
|
||||
network drive. Network drives are generally far slower.
|
||||
|
||||
|
||||
Where is the translate_off command? (How do I ignore a construct?)
|
||||
@@ -313,7 +313,7 @@ Why do I get "unexpected 'do'" or "unexpected 'bit'" errors?
|
||||
|
||||
The words \ ``do``\ , \ ``bit``\ , \ ``ref``\ , \ ``return``\ , and others
|
||||
are reserved keywords in SystemVerilog. Older Verilog code might use these
|
||||
as identifiers. You should change your code to not use them to ensure it
|
||||
as identifiers, and you should change your code to not use them to ensure it
|
||||
works with newer tools. Alternatively, surround them by the Verilog
|
||||
2005/SystemVerilog begin_keywords pragma to indicate Verilog 2001 code.
|
||||
|
||||
@@ -325,7 +325,7 @@ works with newer tools. Alternatively, surround them by the Verilog
|
||||
`end_keywords
|
||||
|
||||
|
||||
If you want the whole design to be parsed as Verilog 2001, see the
|
||||
If you want the whole design parsed as Verilog 2001, see the
|
||||
:vlopt:`--default-language` option.
|
||||
|
||||
|
||||
@@ -342,11 +342,11 @@ Why do I get "undefined reference to sc_time_stamp()?
|
||||
|
||||
In Verilator 4.200 and later, using the timeInc function is recommended
|
||||
instead. See the :ref:`Connecting to C++` examples. Some linkers (MSVC++)
|
||||
still require :code:`sc_time_stamp()` to be defined, either define this
|
||||
still require :code:`sc_time_stamp()` to be defined; either define this
|
||||
with :code:`double sc_time_stamp() { return 0; }` or compile the Verilated
|
||||
code with :code:`-CFLAGS -DVL_TIME_CONTEXT`.
|
||||
|
||||
Prior to Verilator 4.200, the :code:`sc_time_stamp()` function needs to be
|
||||
Before Verilator 4.200, the :code:`sc_time_stamp()` function needs to be
|
||||
defined in C++ (non SystemC) to return the current simulation time.
|
||||
|
||||
|
||||
@@ -369,17 +369,17 @@ also use the "import DPI" SystemVerilog feature to call C code (see the
|
||||
chapter above). There is also limited VPI access to public signals.
|
||||
|
||||
If you want something more complex, since Verilator emits standard C++
|
||||
code, you can write your own C++ routines that can access and modify signal
|
||||
code, you can write C++ routines that can access and modify signal
|
||||
values without needing any PLI interface code, and call it with
|
||||
$c("{any_c++_statement}").
|
||||
|
||||
See the :ref:`Connecting` section.
|
||||
|
||||
|
||||
How do I make a Verilog module that contain a C++ object?
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
How do I make a Verilog module that contains a C++ object?
|
||||
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
You need to add the object to the structure that Verilator creates, then
|
||||
You need to add the object to the structure Verilator creates, then
|
||||
use $c to call a method inside your object. The
|
||||
:file:`test_regress/t/t_extend_class` files in the distribution show an
|
||||
example of how to do this.
|
||||
@@ -388,9 +388,9 @@ example of how to do this.
|
||||
How do I get faster build times?
|
||||
""""""""""""""""""""""""""""""""
|
||||
|
||||
* When running make, pass the make variable VM_PARALLEL_BUILDS=1 so that
|
||||
* When running make, pass the make variable VM_PARALLEL_BUILDS=1, so that
|
||||
builds occur in parallel. Note this is now set by default if an output
|
||||
file was large enough to be split due to the :vlopt:`--output-split`
|
||||
file is large enough to be split due to the :vlopt:`--output-split`
|
||||
option.
|
||||
|
||||
* Verilator emits any infrequently executed "cold" routines into separate
|
||||
@@ -401,17 +401,17 @@ How do I get faster build times?
|
||||
* Use a recent compiler. Newer compilers tend to be faster.
|
||||
|
||||
* Compile in parallel on many machines and use caching; see the web for the
|
||||
ccache, distcc and icecream packages. ccache will skip GCC runs between
|
||||
ccache, distcc, and icecream packages. ccache will skip GCC runs between
|
||||
identical source builds, even across different users. If ccache was
|
||||
installed when Verilator was built it is used, or see OBJCACHE
|
||||
installed when Verilator was built, it is used, or see OBJCACHE
|
||||
environment variable to override this. Also see the
|
||||
:vlopt:`--output-split` option and :ref: `Profiling ccache efficiency`
|
||||
:vlopt:`--output-split` option and :ref: `Profiling ccache efficiency`.
|
||||
|
||||
* To reduce the compile time of classes that use a Verilated module (e.g. a
|
||||
* To reduce the compile time of classes that use a Verilated module (e.g., a
|
||||
top CPP file) you may wish to add a
|
||||
:option:`/*verilator&32;no_inline_module*/` metacomment to your top level
|
||||
:option:`/*verilator&32;no_inline_module*/` metacomment to your top-level
|
||||
module. This will decrease the amount of code in the model's Verilated
|
||||
class, improving compile times of any instantiating top level C++ code,
|
||||
class, improving compile times of any instantiating top-level C++ code,
|
||||
at a relatively small cost of execution performance.
|
||||
|
||||
* Use :ref:`hierarchical verilation`.
|
||||
@@ -421,7 +421,7 @@ Why do so many files need to recompile when I add a signal?
|
||||
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Adding a new signal requires the symbol table to be recompiled. Verilator
|
||||
uses one large symbol table, as that results in 2-3 less assembly
|
||||
uses one large symbol table, resulting in 2-3 fewer assembly
|
||||
instructions for each signal access. This makes the execution time 10-15%
|
||||
faster, but can result in more compilations when something changes.
|
||||
|
||||
@@ -449,8 +449,8 @@ How do I access signals in C?
|
||||
|
||||
The best thing to do is to make a SystemVerilog "export DPI" task or
|
||||
function that accesses that signal, as described in the DPI chapter in the
|
||||
manual and DPI tutorials on the web. This will allow Verilator to better
|
||||
optimize the model and should be portable across simulators.
|
||||
manual and DPI tutorials on the web. This will allow Verilator to
|
||||
optimize the model better and should be portable across simulators.
|
||||
|
||||
If you really want raw access to the signals, declare the signals you will
|
||||
be accessing with a :option:`/*verilator&32;public*/` metacomment before
|
||||
@@ -459,17 +459,17 @@ the signal, as you would any other member variable.
|
||||
|
||||
Signals are the smallest of 8-bit unsigned chars (equivalent to uint8_t),
|
||||
16-bit unsigned shorts (uint16_t), 32-bit unsigned longs (uint32_t), or
|
||||
64-bit unsigned long longs (uint64_t) that fits the width of the signal.
|
||||
64-bit unsigned long longs (uint64_t) that fit the width of the signal.
|
||||
Generally, you can use just uint32_t's for 1 to 32 bits, or uint64_t for
|
||||
1 to 64 bits, and the compiler will properly up-convert smaller entities.
|
||||
Note even signed ports are declared as unsigned; you must sign extend
|
||||
Note that even signed ports are declared as unsigned; you must sign extend
|
||||
yourself to the appropriate signal width.
|
||||
|
||||
Signals wider than 64 bits are stored as an array of 32-bit uint32_t's.
|
||||
Thus to read bits 31:0, access signal[0], and for bits 63:32, access
|
||||
signal[1]. Unused bits (for example bit numbers 65-96 of a 65-bit vector)
|
||||
will always be zero. If you change the value you must make sure to pack
|
||||
zeros in the unused bits or core-dumps may result, because Verilator strips
|
||||
Thus, to read bits 31:0, access signal[0], and for bits 63:32, access
|
||||
signal[1]. Unused bits (for example, bit numbers 65-96 of a 65-bit vector)
|
||||
will always be zero. If you change the value, you must pack
|
||||
zeros in the unused bits, or core-dumps may result because Verilator strips
|
||||
array bound checks where it believes them to be unnecessary to improve
|
||||
performance.
|
||||
|
||||
@@ -490,16 +490,16 @@ From the sc_main.cpp file, you'd then:
|
||||
|
||||
|
||||
In this example, clk is a bool you can read or set as any other variable.
|
||||
The value of normal signals may be set, though clocks shouldn't be changed
|
||||
by your code or you'll get strange results.
|
||||
The value of normal signals may be set, though your code shouldn't change
|
||||
clocks, or you'll get strange results.
|
||||
|
||||
|
||||
Should a module be in Verilog or SystemC?
|
||||
"""""""""""""""""""""""""""""""""""""""""
|
||||
|
||||
Sometimes there is a block that only interconnects instances, and have a
|
||||
choice as to if you write it in Verilog or SystemC. Everything else being
|
||||
equal, best performance is when Verilator sees all of the design. So, look
|
||||
Sometimes there is a block that only interconnects instances, and you have a
|
||||
choice if you write it in Verilog or SystemC. Everything else being
|
||||
equal, the best performance is when Verilator sees all of the design. So, look
|
||||
at the hierarchy of your design, labeling instances as to if they are
|
||||
SystemC or Verilog. Then:
|
||||
|
||||
@@ -510,6 +510,6 @@ SystemC or Verilog. Then:
|
||||
|
||||
* A module with only Verilog instances below can be either, but for best
|
||||
performance should be Verilog. (The exception is if you have a design
|
||||
that is instantiated many times; in this case Verilating one of the lower
|
||||
that is instantiated many times; in this case, Verilating one of the lower
|
||||
modules and instantiating that Verilated instances multiple times into a
|
||||
SystemC module *may* be faster.)
|
||||
|
||||
+15
-9
@@ -50,7 +50,7 @@ For --cc/--sc, it creates:
|
||||
- Make include file with class names (from --make gmake)
|
||||
* - *{prefix}*\ _hier.mk
|
||||
- Make file for hierarchy blocks (from --make gmake)
|
||||
* - *{prefix|*\ _hierMkArgs.f
|
||||
* - *{prefix}*\ _hierMkArgs.f
|
||||
- Arguments for hierarchical Verilation (from --make gmake)
|
||||
* - *{prefix}*\ _hierCMakeArgs.f
|
||||
- Arguments for hierarchical Verilation (from --make cmake)
|
||||
@@ -59,16 +59,20 @@ For --cc/--sc, it creates:
|
||||
* - *{prefix}*\ .cpp
|
||||
- Model C++ file
|
||||
* - *{prefix}*\ ___024root.h
|
||||
- Top level (SystemVerilog $root) internal header file
|
||||
- Top-level internal header file (from SystemVerilog $root)
|
||||
* - *{prefix}*\ ___024root.cpp
|
||||
- Top level (SystemVerilog $root) internal C++ file
|
||||
* - *{prefix}*___024root*{__n}*\ .cpp
|
||||
- Additional top level internal C++ files (from --output-split)
|
||||
- Top-level internal C++ file (from SystemVerilog $root)
|
||||
* - *{prefix}*\ ___024root\ *{__n}*\ .cpp
|
||||
- Additional top-level internal C++ files
|
||||
* - *{prefix}*\ ___024root\ *{__DepSet_hash__n}*\ .cpp
|
||||
- Additional top-level internal C++ files (hashed to reduce build times)
|
||||
* - *{prefix}*\ ___024root__Slow\ *{__n}*\ .cpp
|
||||
- Infrequent cold routines
|
||||
* - *{prefix}*\ ___024root__Trace{__n}*\ .cpp
|
||||
* - *{prefix}*\ ___024root\ *{__DepSet_hash__n}*\ .cpp
|
||||
- Infrequent cold routines (hashed to reduce build times)
|
||||
* - *{prefix}*\ ___024root__Trace\ *{__n}*\ .cpp
|
||||
- Wave file generation code (from --trace)
|
||||
* - *{prefix}*\ ___024root__Trace__Slow{__n}*\ .cpp
|
||||
* - *{prefix}*\ ___024root__Trace__Slow\ *{__n}*\ .cpp
|
||||
- Wave file generation code (from --trace)
|
||||
* - *{prefix}*\ __Dpi.h
|
||||
- DPI import and export declarations (from --dpi)
|
||||
@@ -87,7 +91,9 @@ For --cc/--sc, it creates:
|
||||
* - *{prefix}{each_verilog_module}*\ .cpp
|
||||
- Lower level internal C++ files
|
||||
* - *{prefix}{each_verilog_module}{__n}*\ .cpp
|
||||
- Additional lower C++ files (from --output-split)
|
||||
- Additional lower C++ files
|
||||
* - *{prefix}{each_verilog_module}{__DepSet_hash__n}*\ .cpp
|
||||
- Additional lower C++ files (hashed to reduce build times)
|
||||
|
||||
For --hierarchy mode, it creates:
|
||||
|
||||
@@ -100,7 +106,7 @@ For --hierarchy mode, it creates:
|
||||
* - *{prefix}*\ __hier.dir
|
||||
- Directory to store .dot, .vpp, .tree of top module (from --hierarchy)
|
||||
|
||||
In certain debug and other modes, it also creates:
|
||||
In specific debug and other modes, it also creates:
|
||||
|
||||
.. list-table::
|
||||
|
||||
|
||||
+18
-18
@@ -16,14 +16,14 @@ Package Manager Quick Install
|
||||
|
||||
Using a distribution's package manager is the easiest way to get
|
||||
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:
|
||||
|
||||
::
|
||||
|
||||
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>`__.
|
||||
|
||||
.. _Git Install:
|
||||
@@ -31,8 +31,8 @@ For other distributions refer to `Repology Verilator Distro Packages
|
||||
Git Quick Install
|
||||
=================
|
||||
|
||||
Installing Verilator from Git provides the most flexibility. For additional
|
||||
options and details see :ref:`Detailed Build Instructions` below.
|
||||
Installing Verilator from Git provides the most flexibility; for additional
|
||||
options and details, see :ref:`Detailed Build Instructions` below.
|
||||
|
||||
In brief, to install from git:
|
||||
|
||||
@@ -68,7 +68,7 @@ In brief, to install from git:
|
||||
Detailed Build Instructions
|
||||
===========================
|
||||
|
||||
This section describes details of the build process, and assumes you are
|
||||
This section describes details of the build process and assumes you are
|
||||
building from Git. For using a pre-built binary for your Linux
|
||||
distribution, see instead :ref:`Package Manager Quick Install`.
|
||||
|
||||
@@ -77,11 +77,11 @@ OS Requirements
|
||||
---------------
|
||||
|
||||
Verilator is developed and has primary testing on Ubuntu, with additional
|
||||
testing on FreeBSD and Apple OS-X. Versions have also built on Red Hat
|
||||
Linux, and other flavors of GNU/Linux-ish platforms. Verilator also works
|
||||
on Windows Subsystem for Linux (WSL2), Windows under Cygwin, and Windows
|
||||
under MinGW (gcc -mno-cygwin). Verilated output (not Verilator itself)
|
||||
compiles under all the options above, plus using MSVC++.
|
||||
testing on FreeBSD and Apple OS-X. Versions have also been built on Red Hat
|
||||
Linux, other flavors of GNU/Linux-ish platforms, Windows Subsystem for
|
||||
Linux (WSL2), Windows under Cygwin, and Windows under MinGW (gcc
|
||||
-mno-cygwin). Verilated output (not Verilator itself) compiles under all
|
||||
the options above, plus using MSVC++.
|
||||
|
||||
|
||||
Install Prerequisites
|
||||
@@ -124,7 +124,7 @@ Those developing Verilator itself may also want these (see internals.rst):
|
||||
|
||||
::
|
||||
|
||||
sudo apt-get install gdb graphviz cmake clang clang-format-11 gprof lcov
|
||||
sudo apt-get install gdb graphviz cmake clang clang-format-14 gprof lcov
|
||||
sudo apt-get install yapf3
|
||||
sudo pip3 install sphinx sphinx_rtd_theme sphinxcontrib-spelling breathe
|
||||
cpan install Pod::Perldoc
|
||||
@@ -153,13 +153,13 @@ required at Verilator build time.
|
||||
Obtain Sources
|
||||
--------------
|
||||
|
||||
Get the sources from the git repository: (You need do this only once,
|
||||
Get the sources from the git repository: (You need to do this only once,
|
||||
ever.)
|
||||
|
||||
::
|
||||
|
||||
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:
|
||||
|
||||
@@ -186,7 +186,7 @@ Create the configuration script:
|
||||
Eventual Installation Options
|
||||
-----------------------------
|
||||
|
||||
Before configuring the build, you have to 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
|
||||
the current value of the environment variables :option:`VERILATOR_ROOT`,
|
||||
:option:`SYSTEMC_INCLUDE`, and :option:`SYSTEMC_LIBDIR` as defaults into
|
||||
@@ -220,8 +220,8 @@ the path to all needed files.
|
||||
|
||||
You may eventually be installing onto a project/company-wide "CAD" tools
|
||||
disk that may support multiple versions of every tool. Tell configure the
|
||||
eventual destination directory name. We recommend the destination location
|
||||
include the Verilator version name:
|
||||
eventual destination directory name. We recommend that the destination
|
||||
location include the Verilator version name:
|
||||
|
||||
::
|
||||
|
||||
@@ -255,7 +255,7 @@ as most GNU tools support:
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
./configure --prefix /opt/verilator-VERSION
|
||||
|
||||
Then after installing (below steps) you will need to add
|
||||
Then after installing (below steps), you will need to add
|
||||
``/opt/verilator-VERSION/bin`` to your ``$PATH`` environment variable.
|
||||
|
||||
|
||||
@@ -271,7 +271,7 @@ configure's default system paths:
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
./configure
|
||||
|
||||
Then after installing (below) the binaries should be in a location that is
|
||||
Then after installing (below), the binaries should be in a location
|
||||
already in your ``$PATH`` environment variable.
|
||||
|
||||
|
||||
|
||||
+141
-94
@@ -41,7 +41,7 @@ union, var, void, priority case/if, and unique case/if.
|
||||
It also supports .name and .\* interconnection.
|
||||
|
||||
Verilator partially supports concurrent assert and cover statements; see
|
||||
the enclosed coverage tests for the syntax which is allowed.
|
||||
the enclosed coverage tests for the allowed syntax.
|
||||
|
||||
Verilator has limited support for class and related object-oriented
|
||||
constructs.
|
||||
@@ -58,8 +58,8 @@ function call-like preprocessor defines, default define arguments,
|
||||
SystemVerilog 2017 (IEEE 1800-2017) Support
|
||||
-------------------------------------------
|
||||
|
||||
Verilator supports the 2017 "for" loop constructs, and several minor
|
||||
cleanups IEEE made in 1800-2017.
|
||||
Verilator supports the 2017 "for" loop constructs and several cleanups IEEE
|
||||
made in 1800-2017.
|
||||
|
||||
|
||||
Verilog AMS Support
|
||||
@@ -67,34 +67,99 @@ Verilog AMS Support
|
||||
|
||||
Verilator implements a very small subset of Verilog AMS (Verilog Analog and
|
||||
Mixed-Signal Extensions) with the subset corresponding to those VMS
|
||||
keywords with near equivalents in the Verilog 2005 or SystemVerilog 2009
|
||||
languages.
|
||||
keywords with near-equivalents in Verilog 2005 or SystemVerilog 2017.
|
||||
|
||||
AMS parsing is enabled with :vlopt:`--language VAMS <--language>` or
|
||||
:vlopt:`--language 1800+VAMS <--language>`.
|
||||
|
||||
At present Verilator implements ceil, exp, floor, ln, log, pow, sqrt,
|
||||
string, and wreal.
|
||||
Verilator implements ceil, exp, floor, ln, log, pow, sqrt, string, and
|
||||
wreal.
|
||||
|
||||
|
||||
Synthesis Directive Assertion Support
|
||||
-------------------------------------
|
||||
|
||||
With the :vlopt:`--assert` option, Verilator reads any :code:`//synopsys
|
||||
full_case` or :code:`//synopsys parallel_case` directives. The same
|
||||
applies to any :code:`//ambit synthesis`, :code:`//cadence` or
|
||||
:code:`//pragma` directives of the same form.
|
||||
With the :vlopt:`--assert` option, Verilator reads any
|
||||
|
||||
:code:`//synopsys full_case` or :code:`//synopsys parallel_case`
|
||||
directives. The same applies to any :code:`//ambit synthesis`,
|
||||
:code:`//cadence` or :code:`//pragma` directives of the same form.
|
||||
|
||||
When these synthesis directives are discovered, Verilator will either
|
||||
formally prove the directive to be true, or failing that, will insert the
|
||||
formally prove the directive to be true, or, failing that, will insert the
|
||||
appropriate code to detect failing cases at simulation runtime and print an
|
||||
"Assertion failed" error message.
|
||||
|
||||
Verilator likewise also asserts any "unique" or "priority" SystemVerilog
|
||||
keywords on case statement, as well as "unique" on if statements. However,
|
||||
keywords on case statements, as well as "unique" on if statements. However,
|
||||
"priority if" is currently ignored.
|
||||
|
||||
|
||||
Time
|
||||
====
|
||||
|
||||
With :vlopt:`--timing`, all timing controls are supported:
|
||||
|
||||
* delay statements,
|
||||
* event control statements not only at the top of a process,
|
||||
* intra-assignment timing controls,
|
||||
* net delays,
|
||||
* :code:`wait` statements,
|
||||
|
||||
as well as all flavors of :code:`fork`.
|
||||
|
||||
Compiling a Verilated design that uses these features requires a
|
||||
compiler with C++20 coroutine support, e.g. Clang 5, GCC 10, or newer.
|
||||
|
||||
:code:`#0` delays cause Verilator to issue the :option:`ZERODLY` warning, as
|
||||
they work differently than described in the LRM. They do not schedule process
|
||||
resumption in the Inactive region, though the process will get resumed in the
|
||||
same time slot.
|
||||
|
||||
Rising/falling/turn-off delays are currently unsupported and cause the
|
||||
:option:`RISEFALLDLY` warning.
|
||||
|
||||
Minimum/typical/maximum delays are currently unsupported. The typical delay is
|
||||
always the one chosen. Such expressions cause the :option:`MINTYPMAX` warning.
|
||||
|
||||
Another consequence of using :vlopt:`--timing` is that the :vlopt:`--main`
|
||||
option generates a main file with a proper timing eval loop, eliminating the
|
||||
need for writing any driving C++ code. You can simply compile the
|
||||
simulation (perhaps using :vlopt:`--build`) and run it.
|
||||
|
||||
With :vlopt:`--no-timing`, all timing controls cause the :option:`NOTIMING`
|
||||
error, except:
|
||||
|
||||
* delay statements – they are ignored (as they are in synthesis), though they
|
||||
do issue a :option:`STMTDLY` warning,
|
||||
* intra-assignment timing controls – they are ignored, though they do issue an
|
||||
:option:`ASSIGNDLY` warning,
|
||||
* net delays – they are ignored,
|
||||
* event controls at the top of the procedure,
|
||||
|
||||
Forks cause this error as well, except:
|
||||
|
||||
* forks with no statements,
|
||||
* :code:`fork..join` or :code:`fork..join_any` with one statement,
|
||||
* forks with :vlopt:`--bbox-unsup`.
|
||||
|
||||
If neither :vlopt:`--timing` nor :vlopt:`--no-timing` is specified, all
|
||||
timing controls cause the :option:`NEEDTIMINGOPT` error, except event
|
||||
controls at the top of the process. Forks cause this error as well, except:
|
||||
|
||||
* forks with no statements,
|
||||
* :code:`fork..join` or :code:`fork..join_any` with one statement,
|
||||
* forks with :vlopt:`--bbox-unsup`.
|
||||
|
||||
Timing controls and forks can also be ignored in specific files or parts of
|
||||
files. The :option:`/*verilator&32;timing_off*/` and
|
||||
:option:`/*verilator&32;timing_off*/` metacomments will make Verilator ignore
|
||||
the encompassed timing controls and forks, regardless of the chosen
|
||||
:vlopt:`--timing` or :vlopt:`--no-timing` option. This can also be achieved
|
||||
using the :option:`timing_off` and :option:`timing_off` options in Verilator
|
||||
configuration files.
|
||||
|
||||
|
||||
.. _Language Limitations:
|
||||
|
||||
Language Limitations
|
||||
@@ -108,15 +173,15 @@ Synthesis Subset
|
||||
|
||||
Verilator supports the Synthesis subset with other verification constructs
|
||||
being added over time. Verilator also simulates events as Synopsys's Design
|
||||
Compiler would; namely given a block of the form:
|
||||
Compiler would, namely given a block of the form:
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
always @(x) y = x & z;
|
||||
|
||||
This will recompute y when there is even a potential for change in x or a
|
||||
change in z, that is when the flops computing x or z evaluate (which is
|
||||
what Design Compiler will synthesize.) A compliant simulator would only
|
||||
This will recompute y when there is a potential for change in x or a change
|
||||
in z; that is when the flops computing x or z evaluate (which is what
|
||||
Design Compiler will synthesize.) A compliant simulator will only
|
||||
calculate y if x changes. We recommend using always_comb to make the code
|
||||
run the same everywhere. Also avoid putting $displays in combo blocks, as
|
||||
they may print multiple times when not desired, even on compliant
|
||||
@@ -129,7 +194,7 @@ Signal Naming
|
||||
To avoid conflicts with C symbol naming, any character in a signal name
|
||||
that is not alphanumeric nor a single underscore will be replaced by __0hh
|
||||
where hh is the hex code of the character. To avoid conflicts with
|
||||
Verilator's internal symbols, any double underscore are replaced with
|
||||
Verilator's internal symbols, any double underscore is replaced with
|
||||
___05F (5F is the hex code of an underscore.)
|
||||
|
||||
|
||||
@@ -144,14 +209,13 @@ Class
|
||||
-----
|
||||
|
||||
Verilator class support is limited but in active development. Verilator
|
||||
supports members, and methods. Verilator does not support class static
|
||||
members, class extend, or class parameters.
|
||||
supports members, methods, class extend, and class parameters.
|
||||
|
||||
|
||||
Dotted cross-hierarchy references
|
||||
---------------------------------
|
||||
|
||||
Verilator supports dotted references to variables, functions and tasks in
|
||||
Verilator supports dotted references to variables, functions, and tasks in
|
||||
different modules. The portion before the dot must have a constant value;
|
||||
for example a[2].b is acceptable, while a[x].b is generally not.
|
||||
|
||||
@@ -165,7 +229,7 @@ code.
|
||||
Latches
|
||||
-------
|
||||
|
||||
Verilator is optimized for edge sensitive (flop based) designs. It will
|
||||
Verilator is optimized for edge-sensitive (flop-based) designs. It will
|
||||
attempt to do the correct thing for latches, but most performance
|
||||
optimizations will be disabled around the latch.
|
||||
|
||||
@@ -180,49 +244,43 @@ structure from blocking, and another from non-blocking assignments is
|
||||
unsupported.
|
||||
|
||||
|
||||
Time
|
||||
----
|
||||
|
||||
All delays (#) are ignored, as they are in synthesis.
|
||||
|
||||
|
||||
.. _Unknown States:
|
||||
|
||||
Unknown States
|
||||
--------------
|
||||
|
||||
Verilator is mostly a two state simulator, not a four state simulator.
|
||||
However, it has two features which uncover most initialization bugs
|
||||
(including many that a four state simulator will miss.)
|
||||
Verilator is mostly a two-state simulator, not a four-state simulator.
|
||||
However, it has two features that uncover most initialization bugs
|
||||
(including many that a four-state simulator will miss.)
|
||||
|
||||
Identity comparisons (=== or !==) are converted to standard ==/!= when
|
||||
neither side is a constant. This may make the expression yield a different
|
||||
result compared to a four state simulator. An === comparison to X will
|
||||
result than a four-state simulator. An === comparison to X will
|
||||
always be false, so that Verilog code which checks for uninitialized logic
|
||||
will not fire.
|
||||
|
||||
Assigning X to a variable will actually assign a constant value as
|
||||
determined by the :vlopt:`--x-assign` option. This allows runtime
|
||||
randomization, thus if the value is actually used, the random value should
|
||||
cause downstream errors. Integers also get randomized, even though the
|
||||
Verilog 2001 specification says they initialize to zero. Note however that
|
||||
randomization happens at initialization time and hence during a single
|
||||
simulation run, the same constant (but random) value will be used every
|
||||
time the assignment is executed.
|
||||
Assigning X to a variable will assign a constant value as determined by the
|
||||
:vlopt:`--x-assign` option. This allows runtime randomization; thus, if
|
||||
the value is used, the random value should cause downstream errors.
|
||||
Integers also get randomized, even though the Verilog 2001 specification
|
||||
says they initialize to zero. However, randomization happens at
|
||||
initialization time; hence, during a single simulation run, the same
|
||||
constant (but random) value will be used every time the assignment is
|
||||
executed.
|
||||
|
||||
All variables, depending on :vlopt:`--x-initial` setting, are typically
|
||||
randomly initialized using a function. By running several random
|
||||
simulation runs you can determine that reset is working correctly. On the
|
||||
first run, have the function initialize variables to zero. On the second,
|
||||
have it initialize variables to one. On the third and following runs have
|
||||
it initialize them randomly. If the results match, reset works. (Note
|
||||
this is what the hardware will really do.) In practice, just setting all
|
||||
variables to one at startup finds most problems (since typically control
|
||||
signals are active-high).
|
||||
randomly initialized using a function. You can determine that reset is
|
||||
working correctly by running several random simulation runs. On the first
|
||||
run, have the function initialize variables to zero. On the second, have
|
||||
it initialize variables to one. On the third and following runs, have it
|
||||
initialize them randomly. If the results match, reset works. (Note that
|
||||
this is what the hardware will do.) In practice, setting all variables to
|
||||
one at startup finds the most problems (since control signals are typically
|
||||
active-high).
|
||||
|
||||
:vlopt:`--x-assign` applies to variables explicitly initialized or assigned
|
||||
an X. Uninitialized clocks are initialized to zero, while all other state
|
||||
holding variables are initialized to a random value. Event driven
|
||||
holding variables are initialized to a random value. Event-driven
|
||||
simulators will generally trigger an edge on a transition from X to 1
|
||||
(posedge) or X to 0 (negedge). However, by default, since clocks are
|
||||
initialized to zero, Verilator will not trigger an initial negedge. Some
|
||||
@@ -258,35 +316,24 @@ External logic will be needed to combine these signals with any external
|
||||
drivers.
|
||||
|
||||
Tristate drivers are not supported inside functions and tasks; an inout
|
||||
there will be considered a two state variable that is read and written
|
||||
instead of a four state variable.
|
||||
there will be considered a two-state variable that is read and written
|
||||
instead of a four-state variable.
|
||||
|
||||
|
||||
Functions & Tasks
|
||||
-----------------
|
||||
|
||||
All functions and tasks will be inlined (will not become functions in C.)
|
||||
The only support provided is for simple statements in tasks (which may
|
||||
The only support provided is simple statements in tasks (which may
|
||||
affect global variables).
|
||||
|
||||
Recursive functions and tasks are not supported. All inputs and outputs
|
||||
are automatic, as if they had the Verilog 2001 "automatic" keyword
|
||||
are automatic as if they had the Verilog 2001 "automatic" keyword
|
||||
prepended. (If you don't know what this means, Verilator will do what you
|
||||
probably expect, what C does. The default behavior of Verilog is
|
||||
different.)
|
||||
|
||||
|
||||
Generated Clocks
|
||||
----------------
|
||||
|
||||
Verilator attempts to deal with generated and gated clocks correctly,
|
||||
however some cases cause problems in the scheduling algorithm which is
|
||||
optimized for performance. The safest option is to have all clocks as
|
||||
primary inputs to the model, or wires directly attached to primary inputs.
|
||||
For proper behavior clock enables may also need the
|
||||
:option:`/*verilator&32;clock_enable*/` metacomment.
|
||||
|
||||
|
||||
Gate Primitives
|
||||
---------------
|
||||
|
||||
@@ -313,14 +360,14 @@ error for more information.
|
||||
Array Out of Bounds
|
||||
-------------------
|
||||
|
||||
Writing a memory element that is outside the bounds specified for the array
|
||||
may cause a different memory element inside the array to be written
|
||||
instead. For power-of-2 sized arrays, Verilator will give a width warning
|
||||
and the address. For non-power-of-2-sizes arrays, index 0 will be written.
|
||||
Writing a memory element outside the bounds specified for the array may
|
||||
cause a different memory element inside the array to be written instead.
|
||||
For power-of-2 sized arrays, Verilator will give a width warning and the
|
||||
address. For non-power-of-2-sizes arrays, index 0 will be written.
|
||||
|
||||
Reading a memory element that is outside the bounds specified for the array
|
||||
will give a width warning and wrap around the power-of-2 size. For
|
||||
non-power-of-2 sizes, it will return a unspecified constant of the
|
||||
Reading a memory element outside the bounds specified for the array will
|
||||
give a width warning and wrap around the power-of-2 size. For
|
||||
non-power-of-2 sizes, it will return an unspecified constant of the
|
||||
appropriate width.
|
||||
|
||||
|
||||
@@ -340,14 +387,14 @@ Force statement
|
||||
---------------
|
||||
|
||||
Verilator supports the procedural `force` (and corresponding `release`)
|
||||
statement. The behavior of the `force` statement however does not entirely
|
||||
comply with the IEEE 1800 SystemVerilog standard. According to the standard,
|
||||
statement. However, the behavior of the `force` statement does not entirely
|
||||
comply with IEEE 1800. According to the standard,
|
||||
when a procedural statement of the form `force a = b;` is executed, the
|
||||
simulation should behave as if from that point forwards, a continuous
|
||||
assignment `assign a = b;` have been added to override the drivers of `a`.
|
||||
More specifically: the value of `a` should be updated, whenever the value of
|
||||
`b` changes, all the way until a `release a;` statement is executed.
|
||||
Verilator instead evaluates the current value of `b` at the time the `force`
|
||||
simulation should behave as if, from that point forwards, a continuous
|
||||
assignment `assign a = b;` has been added to override the drivers of `a`.
|
||||
More specifically: the value of `a` should be updated whenever the value of
|
||||
`b` changes, until a `release a;` statement is executed.
|
||||
Verilator instead evaluates the current value of `b` when the `force`
|
||||
statement is executed, and forces `a` to that value, without updating it
|
||||
until a new `force` or `release` statement is encountered that applies to
|
||||
`a`. This non-standard behavior is nevertheless consistent with some other
|
||||
@@ -357,7 +404,7 @@ simulators.
|
||||
Encrypted Verilog
|
||||
-----------------
|
||||
|
||||
Open source simulators like Verilator are unable to use encrypted RTL
|
||||
Open-source simulators like Verilator cannot use encrypted RTL
|
||||
(i.e. IEEE P1735). Talk to your IP vendor about delivering IP blocks via
|
||||
Verilator's :vlopt:`--protect-lib` feature.
|
||||
|
||||
@@ -398,12 +445,12 @@ This section describes specific limitations for each language keyword.
|
||||
certain limited cases.
|
||||
|
||||
'{} operator
|
||||
Assignment patterns with order based, default, constant integer (array)
|
||||
Assignment patterns with an order based, default, constant integer (array)
|
||||
or member identifier (struct/union) keys are supported. Data type keys
|
||||
and keys which are computed from a constant expression are not supported.
|
||||
and keys computed from a constant expression are not supported.
|
||||
|
||||
\`uselib
|
||||
Uselib, a vendor specific library specification method, is ignored along
|
||||
Uselib, a vendor-specific library specification method, is ignored along
|
||||
with anything following it until the end of that line.
|
||||
|
||||
cast operator
|
||||
@@ -411,8 +458,8 @@ cast operator
|
||||
unsigned, not arrays nor structs.
|
||||
|
||||
chandle
|
||||
Treated as a "longint"; does not yet warn about operations that are
|
||||
specified as illegal on chandles.
|
||||
Treated as a "longint"; does not yet warn about operations specified as
|
||||
illegal on chandles.
|
||||
|
||||
disable
|
||||
Disable statements may be used only if the block being disabled is a
|
||||
@@ -425,7 +472,7 @@ inside
|
||||
upper bound. Case inside and case matches are also unsupported.
|
||||
|
||||
interface
|
||||
Interfaces and modports, including with generated data types are
|
||||
Interfaces and modports, including generated data types are
|
||||
supported. Generate blocks around modports are not supported, nor are
|
||||
virtual interfaces nor unnamed interfaces.
|
||||
|
||||
@@ -437,25 +484,25 @@ specify specparam
|
||||
All specify blocks and timing checks are ignored.
|
||||
|
||||
uwire
|
||||
Verilator does not perform warning checking on uwires, it treats the
|
||||
Verilator does not perform warning checking on uwires; it treats the
|
||||
uwire keyword as if it were the normal wire keyword.
|
||||
|
||||
$bits, $countbits, $countones, $finish, $isunknown, $onehot, $onehot0, $signed, $stime, $stop, $time, $unsigned,
|
||||
Generally supported.
|
||||
|
||||
$dump/$dumpports and related
|
||||
$dumpfile or $dumpports will create a VCD or FST file (which is based on
|
||||
$dumpfile or $dumpports will create a VCD or FST file (based on
|
||||
the :vlopt:`--trace` option given when the model was Verilated). This
|
||||
will take effect starting at the next eval() call. If you have multiple
|
||||
Verilated designs under the same C model, then this will dump signals
|
||||
Verilated designs under the same C model, this will dump signals
|
||||
only from the design containing the $dumpvars.
|
||||
|
||||
$dumpvars and $dumpports module identifier is ignored; the traced
|
||||
instances will always start at the top of the design. The levels argument
|
||||
is also ignored, use tracing_on/tracing_off pragmas instead.
|
||||
is also ignored; use tracing_on/tracing_off pragmas instead.
|
||||
|
||||
$dumpportson/$dumpportsoff/$dumpportsall/$dumpportslimit filename
|
||||
argument is ignored, only a single trace file may be active at once.
|
||||
argument is ignored; only a single trace file may be active at once.
|
||||
|
||||
$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and
|
||||
$dumplimit/$dumpportlimit are currently ignored.
|
||||
@@ -464,7 +511,7 @@ $error, $fatal, $info, $warning.
|
||||
Generally supported.
|
||||
|
||||
$exit, $finish, $stop
|
||||
The rarely used optional parameter to $finish and $stop is ignored. $exit
|
||||
The rarely used optional parameter to $finish and $stop is ignored; $exit
|
||||
is aliased to $finish.
|
||||
|
||||
$fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets, $fscanf, $fwrite, $fscanf, $sscanf
|
||||
@@ -480,8 +527,8 @@ $random, $urandom, $urandom_range
|
||||
per object for random stability of $urandom/$urandom_range.
|
||||
|
||||
$readmemb, $readmemh
|
||||
Read memory commands are supported. Note Verilator and the Verilog
|
||||
specification does not include support for readmem to multi-dimensional
|
||||
Read memory commands are supported. Verilator and the Verilog
|
||||
specification do not include support for readmem to multi-dimensional
|
||||
arrays.
|
||||
|
||||
$test$plusargs, $value$plusargs
|
||||
@@ -489,7 +536,7 @@ $test$plusargs, $value$plusargs
|
||||
|
||||
.. code-block:: C++
|
||||
|
||||
Verilated::commandArgs(argc, argv);
|
||||
{VerilatedContext*} ->commandArgs(argc, argv);
|
||||
|
||||
to register the command line before calling $test$plusargs or
|
||||
$value$plusargs.
|
||||
|
||||
+14
-14
@@ -8,30 +8,30 @@ Overview
|
||||
Welcome to Verilator!
|
||||
|
||||
The Verilator package converts Verilog [#]_ and SystemVerilog [#]_ hardware
|
||||
description language (HDL) designs into a C++ or SystemC model that after
|
||||
compiling can be executed. Verilator is not a traditional simulator, but a
|
||||
description language (HDL) designs into a C++ or SystemC model that, after
|
||||
compiling, can be executed. Verilator is not a traditional simulator but a
|
||||
compiler.
|
||||
|
||||
Verilator is typically used as follows:
|
||||
|
||||
1. The :command:`verilator` executable is invoked with parameters similar
|
||||
to GCC, or other simulators such as Cadence Verilog-XL/NC-Verilog, or
|
||||
to GCC or other simulators such as Cadence Verilog-XL/NC-Verilog, or
|
||||
Synopsys VCS. Verilator reads the specified SystemVerilog code, lints it,
|
||||
optionally adds coverage and waveform tracing support, and compiles the
|
||||
design into a source level multithreaded C++ or SystemC "model". The
|
||||
design into a source-level multithreaded C++ or SystemC "model". The
|
||||
resulting model's C++ or SystemC code is output as .cpp and .h files. This
|
||||
is referred to as "Verilating" and the process is "to Verilate"; the output
|
||||
is a "Verilated" model.
|
||||
is referred to as "Verilating", and the process is "to Verilate"; the
|
||||
output is a "Verilated" model.
|
||||
|
||||
2. For simulation, a small user written C++ wrapper file is required, the
|
||||
"wrapper". This wrapper defines the C++ standard function "main()" which
|
||||
2. For simulation, a small-user written C++ wrapper file is required, the
|
||||
"wrapper". This wrapper defines the C++ standard function "main()", which
|
||||
instantiates the Verilated model as a C++/SystemC object.
|
||||
|
||||
3. The user C++ wrapper, the files created by Verilator, a "runtime
|
||||
library" provided by Verilator, and if applicable SystemC libraries are
|
||||
library" provided by Verilator, and, if applicable SystemC libraries are
|
||||
then compiled using a C++ compiler to create a simulation executable.
|
||||
|
||||
4. The resulting executable will perform the actual simulation, during
|
||||
4. The resulting executable will perform the actual simulation during
|
||||
"simulation runtime".
|
||||
|
||||
5. If appropriately enabled, the executable may also generate waveform
|
||||
@@ -44,12 +44,12 @@ The best place to get started is to try the :ref:`Examples`.
|
||||
.. [#] Verilog is defined by the `Institute of Electrical and Electronics
|
||||
Engineers (IEEE) Standard for Verilog Hardware Description
|
||||
Language`, Std. 1364, released in 1995, 2001, and 2005. The
|
||||
Verilator documentation uses the shorthand e.g. "IEEE 1394-2005" to
|
||||
refer to the e.g. 2005 version of this standard.
|
||||
Verilator documentation uses the shorthand, e.g., "IEEE 1394-2005",
|
||||
to refer to the, e.g., 2005 version of this standard.
|
||||
|
||||
.. [#] SystemVerilog is defined by the `Institute of Electrical and
|
||||
Electronics Engineers (IEEE) Standard for SystemVerilog - Unified
|
||||
Hardware Design, Specification, and Verification Language`, Standard
|
||||
1800, released in 2005, 2009, 2012, and 2017. The Verilator
|
||||
documentation uses the shorthand e.g. "IEEE 1800-2017" to refer to
|
||||
the e.g. 2017 version of this standard.
|
||||
documentation uses the shorthand e.g., "IEEE 1800-2017", to refer to
|
||||
the, e.g., 2017 version of this standard.
|
||||
|
||||
+124
-123
@@ -7,9 +7,9 @@
|
||||
Simulating (Verilated-Model Runtime)
|
||||
************************************
|
||||
|
||||
This section describes items related to simulating, that using a Verilated
|
||||
model's executable. For the runtime arguments to a simulated model, see
|
||||
:ref:`Simulation Runtime Arguments`.
|
||||
This section describes items related to simulating, that is, using a
|
||||
Verilated model's executable. For the runtime arguments to a simulated
|
||||
model, see :ref:`Simulation Runtime Arguments`.
|
||||
|
||||
|
||||
.. _Benchmarking & Optimization:
|
||||
@@ -18,30 +18,32 @@ Benchmarking & Optimization
|
||||
===========================
|
||||
|
||||
For best performance, run Verilator with the :vlopt:`-O3`
|
||||
:vlopt:`--x-assign fast <--x-assign>` :vlopt:`--x-initial fast
|
||||
<--x-initial>` :vlopt:`--noassert <--assert>` options. The :vlopt:`-O3`
|
||||
option will require longer time to run Verilator, and :vlopt:`--x-assign
|
||||
fast <--x-assign>` :vlopt:`--x-initial fast <--x-assign>` may increase the
|
||||
risk of reset bugs in trade for performance; see the above documentation
|
||||
for these options.
|
||||
:vlopt:`--x-assign fast <--x-assign>`
|
||||
:vlopt:`--x-initial fast <--x-initial>`
|
||||
:vlopt:`--noassert <--assert>` options. The :vlopt:`-O3`
|
||||
option will require a longer time to run Verilator, and
|
||||
:vlopt:`--x-assign fast <--x-assign>`
|
||||
:vlopt:`--x-initial fast <--x-assign>`
|
||||
may increase the risk of reset bugs in trade for performance; see the above
|
||||
documentation for these options.
|
||||
|
||||
If using Verilated multithreaded, use ``numactl`` to ensure you are using
|
||||
non-conflicting hardware resources. See :ref:`Multithreading`. Also
|
||||
consider using profile-guided optimization, see :ref:`Thread PGO`.
|
||||
If using Verilated multithreaded, use ``numactl`` to ensure you use
|
||||
non-conflicting hardware resources. See :ref:`Multithreading`. Also,
|
||||
consider using profile-guided optimization; see :ref:`Thread PGO`.
|
||||
|
||||
Minor Verilog code changes can also give big wins. You should not have any
|
||||
UNOPTFLAT warnings from Verilator. Fixing these warnings can result in
|
||||
huge improvements; one user fixed their one UNOPTFLAT warning by making a
|
||||
simple change to a clock latch used to gate clocks and gained a 60%
|
||||
performance improvement.
|
||||
:option:`UNOPTFLAT` warnings from Verilator. Fixing these warnings can
|
||||
result in huge improvements; one user fixed their one UNOPTFLAT warning by
|
||||
making a simple change to a clocked latch used to gate clocks and gained a
|
||||
60% performance improvement.
|
||||
|
||||
Beyond that, the performance of a Verilated model depends mostly on your
|
||||
C++ compiler and size of your CPU's caches. Experience shows that large
|
||||
models are often limited by the size of the instruction cache, and as such
|
||||
reducing code size if possible can be beneficial.
|
||||
Beyond that, the performance of a Verilated model depends primarily on your
|
||||
C++ compiler and the size of your CPU's caches. Experience shows that the
|
||||
instruction cache size often limits large models, and reducing code size,
|
||||
if possible, can be beneficial.
|
||||
|
||||
The supplied $VERILATOR_ROOT/include/verilated.mk file uses the OPT,
|
||||
OPT_FAST, OPT_SLOW and OPT_GLOBAL variables to control optimization. You
|
||||
OPT_FAST, OPT_SLOW, and OPT_GLOBAL variables to control optimization. You
|
||||
can set these when compiling the output of Verilator with Make, for
|
||||
example:
|
||||
|
||||
@@ -49,17 +51,17 @@ example:
|
||||
|
||||
make OPT_FAST="-Os -march=native" -f Vour.mk Vour__ALL.a
|
||||
|
||||
OPT_FAST specifies optimization options for those parts of the model that
|
||||
are on the fast path. This is mostly code that is executed every
|
||||
cycle. OPT_SLOW applies to slow-path code, which executes rarely, often
|
||||
only once at the beginning or end of simulation. Note that OPT_SLOW is
|
||||
OPT_FAST specifies optimization options for those parts of the model
|
||||
on the fast path. This is mostly code that is executed every
|
||||
cycle. OPT_SLOW applies to slow-path code, which rarely executes, often
|
||||
only once at the beginning or end of the simulation. OPT_SLOW is
|
||||
ignored if VM_PARALLEL_BUILDS is not 1, in which case all generated code
|
||||
will be compiled in a single compilation unit using OPT_FAST. See also the
|
||||
Verilator :vlopt:`--output-split` option. The OPT_GLOBAL variable applies
|
||||
to common code in the runtime library used by Verilated models (shipped in
|
||||
$VERILATOR_ROOT/include). Additional C++ files passed on the verilator
|
||||
command line use OPT_FAST. The OPT variable applies to all compilation
|
||||
units in addition to the specific "OPT" variables described above.
|
||||
units and the specific "OPT" variables described above.
|
||||
|
||||
You can also use the :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options on
|
||||
the verilator command line to pass arguments directly to the compiler or
|
||||
@@ -68,53 +70,53 @@ linker.
|
||||
The default values of the "OPT" variables are chosen to yield good
|
||||
simulation speed with reasonable C++ compilation times. To this end,
|
||||
OPT_FAST is set to "-Os" by default. Higher optimization such as "-O2" or
|
||||
"-O3" may help (though often they provide only a very small performance
|
||||
benefit), but compile times may be excessively large even with medium sized
|
||||
"-O3" may help (though often they provide only a minimal performance
|
||||
benefit), but compile times may be excessively large even with medium-sized
|
||||
designs. Compilation times can be improved at the expense of simulation
|
||||
speed by reducing optimization, for example with OPT_FAST="-O0". Often good
|
||||
simulation speed can be achieved with OPT_FAST="-O1 -fstrict-aliasing" but
|
||||
with improved compilation times. Files controlled by OPT_SLOW have little
|
||||
effect on performance and therefore OPT_SLOW is empty by default
|
||||
(equivalent to "-O0") for improved compilation speed. In common use-cases
|
||||
speed by reducing optimization, for example, with OPT_FAST="-O0". Often
|
||||
good simulation speed can be achieved with OPT_FAST="-O1 -fstrict-aliasing"
|
||||
but with improved compilation times. Files controlled by OPT_SLOW have
|
||||
little effect on performance, and therefore OPT_SLOW is empty by default
|
||||
(equivalent to "-O0") for improved compilation speed. In common use cases,
|
||||
there should be little benefit in changing OPT_SLOW. OPT_GLOBAL is set to
|
||||
"-Os" by default and there should rarely be a need to change it. As the
|
||||
runtime library is small in comparison to a lot of Verilated models,
|
||||
disabling optimization on the runtime library should not have a serious
|
||||
effect on overall compilation time, but may have detrimental effect on
|
||||
simulation speed, especially with tracing. In addition to the above, for
|
||||
best results use OPT="-march=native", the latest Clang compiler (about 10%
|
||||
faster than GCC), and link statically.
|
||||
"-Os" by default, and there should rarely be a need to change it. As the
|
||||
runtime library is small compared to many Verilated models, disabling
|
||||
optimization on the runtime library should not seriously affect overall
|
||||
compilation time but may have a detrimental effect on simulation speed,
|
||||
especially with tracing. In addition to the above, for best results, use
|
||||
OPT="-march=native", the latest Clang compiler (about 10% faster than GCC),
|
||||
and link statically.
|
||||
|
||||
Generally the answer to which optimization level gives the best user
|
||||
experience depends on the use case and some experimentation can pay
|
||||
Generally, the answer to which optimization level gives the best user
|
||||
experience depends on the use case, and some experimentation can pay
|
||||
dividends. For a speedy debug cycle during development, especially on large
|
||||
designs where C++ compilation speed can dominate, consider using lower
|
||||
optimization to get to an executable faster. For throughput oriented use
|
||||
cases, for example regressions, it is usually worth spending extra
|
||||
optimization to get to an executable faster. For throughput-oriented use
|
||||
cases, for example, regressions, it is usually worth spending extra
|
||||
compilation time to reduce total CPU time.
|
||||
|
||||
If you will be running many simulations on a single model, you can
|
||||
investigate profile guided optimization. See :ref:`Compiler PGO`.
|
||||
investigate profile-guided optimization. See :ref:`Compiler PGO`.
|
||||
|
||||
Modern compilers also support link-time optimization (LTO), which can help
|
||||
Modern compilers also support link-time optimization (LTO), which can help,
|
||||
especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in
|
||||
both compilation and link. Note LTO may cause excessive compile times on
|
||||
large designs.
|
||||
both compilation and link. Note that LTO may cause excessive compile times
|
||||
on large designs.
|
||||
|
||||
Unfortunately, using the optimizer with SystemC files can result in
|
||||
compilation taking several minutes. (The SystemC libraries have many little
|
||||
inlined functions that drive the compiler nuts.)
|
||||
|
||||
If you are using your own makefiles, you may want to compile the Verilated
|
||||
If using your own makefiles, you may want to compile the Verilated
|
||||
code with ``--MAKEFLAGS -DVL_INLINE_OPT=inline``. This will inline
|
||||
functions, however this requires that all cpp files be compiled in a single
|
||||
functions; however, this requires that all cpp files be compiled in a single
|
||||
compiler run.
|
||||
|
||||
You may uncover further tuning possibilities by profiling the Verilog code.
|
||||
See :ref:`profiling`.
|
||||
|
||||
When done optimizing, please let the author know the results. We like to
|
||||
keep tabs on how Verilator compares, and may be able to suggest additional
|
||||
keep tabs on how Verilator compares and may be able to suggest additional
|
||||
improvements.
|
||||
|
||||
|
||||
@@ -141,14 +143,14 @@ Functional Coverage
|
||||
-------------------
|
||||
|
||||
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
|
||||
translate functional coverage points which the user has inserted manually
|
||||
into the SystemVerilog design, into the Verilated model.
|
||||
translate functional coverage points the user has inserted manually win
|
||||
SystemVerilog code through into the Verilated model.
|
||||
|
||||
Currently, all functional coverage points are specified using SystemVerilog
|
||||
assertion syntax which must be separately enabled with :vlopt:`--assert`.
|
||||
assertion syntax, which must be separately enabled with :vlopt:`--assert`.
|
||||
|
||||
For example, the following SystemVerilog statement will add a coverage
|
||||
point, under the coverage name "DefaultClock":
|
||||
point under the coverage name "DefaultClock":
|
||||
|
||||
.. code-block:: sv
|
||||
|
||||
@@ -161,13 +163,13 @@ Line Coverage
|
||||
-------------
|
||||
|
||||
With :vlopt:`--coverage` or :vlopt:`--coverage-line`, Verilator will
|
||||
automatically add coverage analysis at each code flow change point (e.g. at
|
||||
branches). At each such branch a unique counter is incremented. At the
|
||||
end of a test, the counters along with the filename and line number
|
||||
corresponding to each counter are written into the coverage file.
|
||||
automatically add coverage analysis at each code flow change point (e.g.,
|
||||
at branches). At each such branch, a counter is incremented. At the end
|
||||
of a test, the counters, filename, and line number corresponding to each
|
||||
counter are written into the coverage file.
|
||||
|
||||
Verilator automatically disables coverage of branches that have a $stop in
|
||||
them, as it is assumed $stop branches contain an error check that should
|
||||
Verilator automatically disables coverage of branches with a $stop in
|
||||
them, as it is assumed that $stop branches contain an error check that should
|
||||
not occur. A :option:`/*verilator&32;coverage_block_off*/` metacomment
|
||||
will perform a similar function on any code in that block or below, or
|
||||
:option:`/*verilator&32;coverage_off*/` and
|
||||
@@ -175,8 +177,9 @@ will perform a similar function on any code in that block or below, or
|
||||
respectively around a block of code.
|
||||
|
||||
Verilator may over-count combinatorial (non-clocked) blocks when those
|
||||
blocks receive signals which have had the UNOPTFLAT warning disabled; for
|
||||
most accurate results do not disable this warning when using coverage.
|
||||
blocks receive signals which have had the :option:`UNOPTFLAT` warning
|
||||
disabled; for the most accurate results, do not disable this warning when
|
||||
using coverage.
|
||||
|
||||
|
||||
.. _Toggle Coverage:
|
||||
@@ -187,8 +190,8 @@ Toggle Coverage
|
||||
With :vlopt:`--coverage` or :vlopt:`--coverage-toggle`, Verilator will
|
||||
automatically add toggle coverage analysis into the Verilated model.
|
||||
|
||||
Every bit of every signal in a module has a counter inserted. The counter
|
||||
will increment on every edge change of the corresponding bit.
|
||||
Every bit of every signal in a module has a counter inserted, and the
|
||||
counter will increment on every edge change of the corresponding bit.
|
||||
|
||||
Signals that are part of tasks or begin/end blocks are considered local
|
||||
variables and are not covered. Signals that begin with underscores (see
|
||||
@@ -196,17 +199,17 @@ variables and are not covered. Signals that begin with underscores (see
|
||||
total storage across all dimensions, see :vlopt:`--coverage-max-width`) are
|
||||
also not covered.
|
||||
|
||||
Hierarchy is compressed, such that if a module is instantiated multiple
|
||||
times, coverage will be summed for that bit across **all** instantiations
|
||||
of that module with the same parameter set. A module instantiated with
|
||||
different parameter values is considered a different module, and will get
|
||||
counted separately.
|
||||
Hierarchy is compressed, so if a module is instantiated multiple times,
|
||||
coverage will be summed for that bit across **all** instantiations of that
|
||||
module with the same parameter set. A module instantiated with different
|
||||
parameter values is considered a different module and will get counted
|
||||
separately.
|
||||
|
||||
Verilator makes a minimally-intelligent decision about what clock domain
|
||||
the signal goes to, and only looks for edges in that clock domain. This
|
||||
means that edges may be ignored if it is known that the edge could never be
|
||||
seen by the receiving logic. This algorithm may improve in the future.
|
||||
The net result is coverage may be lower than what would be seen by looking
|
||||
means that edges may be ignored if it is known that the receiving logic
|
||||
could never see the edge. This algorithm may improve in the future. The
|
||||
net result is that coverage may be lower than what would be seen by looking
|
||||
at traces, but the coverage is a more accurate representation of the
|
||||
quality of stimulus into the design.
|
||||
|
||||
@@ -224,7 +227,7 @@ signals that do not need toggle analysis, such as RAMs and register files.
|
||||
Coverage Collection
|
||||
-------------------
|
||||
|
||||
When any coverage flag was used to Verilate, Verilator will add appropriate
|
||||
When any coverage flag is used to Verilate, Verilator will add appropriate
|
||||
coverage point insertions into the model and collect the coverage data.
|
||||
|
||||
To get the coverage data from the model, in the user wrapper code,
|
||||
@@ -237,23 +240,23 @@ Run each of your tests in different directories, potentially in parallel.
|
||||
Each test will create a :file:`logs/coverage.dat` file.
|
||||
|
||||
After running all of the tests, execute the :command:`verilator_coverage`
|
||||
command, passing arguments pointing to the filenames of all of the
|
||||
individual coverage files. :command:`verilator_coverage` will reads the
|
||||
command, passing arguments pointing to the filenames of all the
|
||||
individual coverage files. :command:`verilator_coverage` will read the
|
||||
:file:`logs/coverage.dat` file(s), and create an annotated source code
|
||||
listing showing code coverage details.
|
||||
|
||||
:command:`verilator_coverage` may also be used for test grading, that is
|
||||
computing which tests are important to fully cover the design.
|
||||
:command:`verilator_coverage` may also be used for test grading, computing
|
||||
which tests are important to give full verification coverage on the design.
|
||||
|
||||
For an example, see the :file:`examples/make_tracing_c/logs` directory.
|
||||
Grep for lines starting with '%' to see what lines Verilator believes need
|
||||
more coverage.
|
||||
|
||||
Additional options of :command:`verilator_coverage` allow for merging of
|
||||
coverage data files or other transformations.
|
||||
Additional options of :command:`verilator_coverage` allow for the merging
|
||||
of coverage data files or other transformations.
|
||||
|
||||
Info files can be written by verilator_coverage for import to
|
||||
:command:`lcov`. This enables use of :command:`genhtml` for HTML reports
|
||||
:command:`lcov`. This enables using :command:`genhtml` for HTML reports
|
||||
and importing reports to sites such as `https://codecov.io
|
||||
<https://codecov.io>`_.
|
||||
|
||||
@@ -274,7 +277,7 @@ To use profiling:
|
||||
#. Build and run the simulation model.
|
||||
#. The model will create gmon.out.
|
||||
#. Run :command:`gprof` to see where in the C++ code the time is spent.
|
||||
#. Run the gprof output through the :command:`verilator_profcfunc` program
|
||||
#. Run the gprof output through the :command:`verilator_profcfunc` program,
|
||||
and it will tell you what Verilog line numbers on which most of the time
|
||||
is being spent.
|
||||
|
||||
@@ -284,7 +287,7 @@ To use profiling:
|
||||
Execution Profiling
|
||||
===================
|
||||
|
||||
For performance optimization, it is useful to see statistics and visualize how
|
||||
For performance optimization, it is helpful to see statistics and visualize how
|
||||
execution time is distributed in a verilated model.
|
||||
|
||||
With the :vlopt:`--prof-exec` option, Verilator will:
|
||||
@@ -294,14 +297,13 @@ With the :vlopt:`--prof-exec` option, Verilator will:
|
||||
* Add code to save profiling data in non-human-friendly form to the file
|
||||
specified with :vlopt:`+verilator+prof+exec+file+\<filename\>`.
|
||||
|
||||
* In multi-threaded models, add code to record the start and end time of each
|
||||
macro-task across a number of calls to eval. (What is a macro-task? See the
|
||||
* In multithreaded models, add code to record each macro-task's start and
|
||||
end time across several calls to eval. (What is a macro-task? See the
|
||||
Verilator internals document (:file:`docs/internals.rst` in the
|
||||
distribution.)
|
||||
|
||||
The :command:`verilator_gantt` program may then be run to transform the
|
||||
saved profiling file into a nicer visual format and produce some related
|
||||
statistics.
|
||||
saved profiling file into a visual format and produce related statistics.
|
||||
|
||||
.. figure:: figures/fig_gantt_min.png
|
||||
|
||||
@@ -309,11 +311,11 @@ statistics.
|
||||
|
||||
The measured_parallelism shows the number of CPUs being used at a given moment.
|
||||
|
||||
The cpu_thread section shows which thread is executing on each of the physical CPUs.
|
||||
The cpu_thread section shows which thread is executing on each physical CPU.
|
||||
|
||||
The thread_mtask section shows which macro-task is running on a given thread.
|
||||
|
||||
For more information see :command:`verilator_gantt`.
|
||||
For more information, see :command:`verilator_gantt`.
|
||||
|
||||
|
||||
.. _Profiling ccache efficiency:
|
||||
@@ -321,12 +323,11 @@ For more information see :command:`verilator_gantt`.
|
||||
Profiling ccache efficiency
|
||||
===========================
|
||||
|
||||
The Verilator generated Makefile provides support for basic profiling of
|
||||
ccache behavior during the build. This can be used to track down files that
|
||||
might be unnecessarily rebuilt, though as of today even small code changes
|
||||
will usually require rebuilding a large number of files. Improving ccache
|
||||
efficiency during the edit/compile/test loop is an active area of
|
||||
development.
|
||||
The Verilator-generated Makefile supports basic profiling of ccache
|
||||
behavior during the build. This can be used to track down files that might
|
||||
be unnecessarily rebuilt, though as of today, even minor code changes will
|
||||
usually require rebuilding a large number of files. Improving ccache
|
||||
efficiency during the edit/compile/test loop is an active development area.
|
||||
|
||||
To get a basic report of how well ccache is doing, add the `ccache-report`
|
||||
target when invoking the generated Makefile:
|
||||
@@ -350,17 +351,17 @@ releases.
|
||||
Save/Restore
|
||||
============
|
||||
|
||||
The intermediate state of a Verilated model may be saved, so that it may
|
||||
The intermediate state of a Verilated model may be saved so that it may
|
||||
later be restored.
|
||||
|
||||
To enable this feature, use :vlopt:`--savable`. There are limitations in
|
||||
what language features are supported along with :vlopt:`--savable`; if you
|
||||
attempt to use an unsupported feature Verilator will throw an error.
|
||||
attempt to use an unsupported feature, Verilator will throw an error.
|
||||
|
||||
To use save/restore, the user wrapper code must create a VerilatedSerialize
|
||||
or VerilatedDeserialze object then calling the :code:`<<` or :code:`>>`
|
||||
operators on the generated model and any other data the process needs
|
||||
saved/restored. These functions are not thread safe, and are typically
|
||||
or VerilatedDeserialze object and then call the :code:`<<` or :code:`>>`
|
||||
operators on the generated model and any other data the process needs to be
|
||||
saved/restored. These functions are not thread-safe and are typically
|
||||
called only by a main thread.
|
||||
|
||||
For example:
|
||||
@@ -370,7 +371,7 @@ For example:
|
||||
void save_model(const char* filenamep) {
|
||||
VerilatedSave os;
|
||||
os.open(filenamep);
|
||||
os << main_time; // user code must save the timestamp, etc
|
||||
os << main_time; // user code must save the timestamp
|
||||
os << *topp;
|
||||
}
|
||||
void restore_model(const char* filenamep) {
|
||||
@@ -385,11 +386,11 @@ Profile-Guided Optimization
|
||||
===========================
|
||||
|
||||
Profile-guided optimization is the technique where profiling data is
|
||||
collected by running your simulation executable, then this information is
|
||||
collected by running your simulation executable; then this information is
|
||||
used to guide the next Verilation or compilation.
|
||||
|
||||
There are two forms of profile-guided optimizations. Unfortunately for
|
||||
best results they must each be performed from the highest level code to the
|
||||
There are two forms of profile-guided optimizations. Unfortunately, for
|
||||
best results, they must each be performed from the highest level code to the
|
||||
lowest, which means performing them separately and in this order:
|
||||
|
||||
* :ref:`Thread PGO`
|
||||
@@ -397,7 +398,7 @@ lowest, which means performing them separately and in this order:
|
||||
|
||||
Other forms of PGO may be supported in the future, such as clock and reset
|
||||
toggle rate PGO, branch prediction PGO, statement execution time PGO, or
|
||||
others as they prove beneficial.
|
||||
others, as they prove beneficial.
|
||||
|
||||
|
||||
.. _Thread PGO:
|
||||
@@ -405,7 +406,7 @@ others as they prove beneficial.
|
||||
Thread Profile-Guided Optimization
|
||||
----------------------------------
|
||||
|
||||
Verilator supports profile-guided optimization (Verilation) of multi-threaded
|
||||
Verilator supports profile-guided optimization (Verilation) of multithreaded
|
||||
models (Thread PGO) to improve performance.
|
||||
|
||||
When using multithreading, Verilator computes how long macro tasks take and
|
||||
@@ -423,24 +424,24 @@ optimization.
|
||||
Run the model executable. When the executable exits, it will create a
|
||||
profile.vlt file.
|
||||
|
||||
Rerun Verilator, optionally omitting the :vlopt:`--prof-pgo` option,
|
||||
and adding the profile.vlt generated earlier to the command line.
|
||||
Rerun Verilator, optionally omitting the :vlopt:`--prof-pgo` option and
|
||||
adding the :file:`profile.vlt` generated earlier to the command line.
|
||||
|
||||
Note there is no Verilator equivalent to GCC's --fprofile-use. Verilator's
|
||||
profile data file (profile.vlt) can be placed on the verilator command line
|
||||
directly without any prefix.
|
||||
Note there is no Verilator equivalent to GCC's --fprofile-use. Verilator's
|
||||
profile data file (:file:`profile.vlt`) can be placed directly on the
|
||||
verilator command line without any option prefix.
|
||||
|
||||
If results from multiple simulations are to be used in generating the
|
||||
optimization, multiple simulation's profile.vlt may be concatenated
|
||||
externally, or each of the files may be fed as separate command line
|
||||
options into Verilator. Verilator will sum the profile results, so a
|
||||
longer running test will have proportionally more weight for optimization
|
||||
than a shorter running test.
|
||||
externally, or each file may be fed as separate command line options into
|
||||
Verilator. Verilator will sum the profile results, so a long-running test
|
||||
will have more weight for optimization proportionally than a
|
||||
shorter-running test.
|
||||
|
||||
If you provide any profile feedback data to Verilator, and it cannot use
|
||||
If you provide any profile feedback data to Verilator and it cannot use
|
||||
it, it will issue the :option:`PROFOUTOFDATE` warning that threads were
|
||||
scheduled using estimated costs. This usually indicates that the profile
|
||||
data was generated from different Verilog source code than Verilator is
|
||||
data was generated from a different Verilog source code than Verilator is
|
||||
currently running against. Therefore, repeat the data collection phase to
|
||||
create new profiling data, then rerun Verilator with the same input source
|
||||
files and that new profiling data.
|
||||
@@ -452,12 +453,12 @@ Compiler Profile-Guided Optimization
|
||||
------------------------------------
|
||||
|
||||
GCC and Clang support compiler profile-guided optimization (PGO). This
|
||||
optimizes any C/C++ program including Verilated code. Using compiler PGO
|
||||
optimizes any C/C++ program, including Verilated code. Using compiler PGO
|
||||
typically yields improvements of 5-15% on both single-threaded and
|
||||
multi-threaded models.
|
||||
multithreaded models.
|
||||
|
||||
To use compiler PGO with GCC or Clang, please see the appropriate compiler
|
||||
documentation. The process in GCC 10 was as follows:
|
||||
Please see the appropriate compiler documentation to use PGO with GCC or
|
||||
Clang. The process in GCC 10 was as follows:
|
||||
|
||||
1. Compile the Verilated model with the compiler's "-fprofile-generate"
|
||||
flag:
|
||||
@@ -467,7 +468,7 @@ documentation. The process in GCC 10 was as follows:
|
||||
verilator [whatever_flags] --make \
|
||||
-CFLAGS -fprofile-generate -LDFLAGS -fprofile-generate
|
||||
|
||||
or, if calling make yourself, add -fprofile-generate appropriately to your
|
||||
Or, if calling make yourself, add -fprofile-generate appropriately to your
|
||||
Makefile.
|
||||
|
||||
2. Run your simulation. This will create \*.gcda file(s) in the same
|
||||
@@ -494,6 +495,6 @@ documentation. The process in GCC 10 was as follows:
|
||||
or, if calling make yourself, add these CFLAGS switches appropriately to
|
||||
your Makefile.
|
||||
|
||||
Clang and GCC also support -fauto-profile which uses sample-based
|
||||
Clang and GCC also support -fauto-profile, which uses sample-based
|
||||
feedback-directed optimization. See the appropriate compiler
|
||||
documentation.
|
||||
|
||||
+86
-98
@@ -8,7 +8,7 @@ Verilating
|
||||
Verilator may be used in five major ways:
|
||||
|
||||
* With the :vlopt:`--cc` or :vlopt:`--sc` options, Verilator will translate
|
||||
the design into C++ or SystemC code respectively. See :ref:`C++ and
|
||||
the design into C++ or SystemC code, respectively. See :ref:`C++ and
|
||||
SystemC Generation`.
|
||||
|
||||
* With the :vlopt:`--lint-only` option, Verilator will lint the design to
|
||||
@@ -19,8 +19,8 @@ Verilator may be used in five major ways:
|
||||
:file:`docs/xml.rst` in the distribution.
|
||||
|
||||
* With the :vlopt:`-E` option, Verilator will preprocess the code according
|
||||
to IEEE preprocessing rules, and write the output to standard out. This
|
||||
is useful to feed other tools, and to debug how "\`define" statements are
|
||||
to IEEE preprocessing rules and write the output to standard out. This
|
||||
is useful to feed other tools and to debug how "\`define" statements are
|
||||
expanded.
|
||||
|
||||
|
||||
@@ -34,10 +34,10 @@ Verilator will translate a SystemVerilog design into C++ with the
|
||||
|
||||
When using these options:
|
||||
|
||||
#. Verilator reads the input Verilog code, determines all "top modules" that
|
||||
is modules or programs that are not used as instances under other cells.
|
||||
If :vlopt:`--top-module` is used, then that determines the top module and
|
||||
all other top modules are removed, otherwise a :vlopt:`MULTITOP` warning
|
||||
#. Verilator reads the input Verilog code and determines all "top modules", that
|
||||
is, modules or programs that are not used as instances under other cells.
|
||||
If :vlopt:`--top-module` is used, then that determines the top module, and
|
||||
all other top modules are removed; otherwise a :vlopt:`MULTITOP` warning
|
||||
is given.
|
||||
|
||||
#. Verilator writes the C++/SystemC code to output files into the
|
||||
@@ -46,13 +46,13 @@ When using these options:
|
||||
top module.
|
||||
|
||||
#. If :vlopt:`--exe` is used, Verilator creates makefiles to generate a
|
||||
simulation executable, otherwise it creates makefiles to generate an
|
||||
simulation executable, otherwise, it creates makefiles to generate an
|
||||
archive (.a) containing the objects.
|
||||
|
||||
#. If :vlopt:`--build` option was used, it calls :ref:`GNU Make` or
|
||||
:ref:`CMake` to build the model.
|
||||
|
||||
Once a model is built it is then typically run, see :ref:`Simulating`.
|
||||
Once a model is built, it is then typically run, see :ref:`Simulating`.
|
||||
|
||||
|
||||
.. _Hierarchical Verilation:
|
||||
@@ -60,14 +60,14 @@ Once a model is built it is then typically run, see :ref:`Simulating`.
|
||||
Hierarchical Verilation
|
||||
=======================
|
||||
|
||||
Large designs may take long (e.g. 10+ minutes) and huge memory (e.g. 100+
|
||||
Large designs may take long (e.g., 10+ minutes) and huge memory (e.g., 100+
|
||||
GB) to Verilate. In hierarchical mode, the user manually selects some
|
||||
large lower-level hierarchy blocks to separate from the larger design. For
|
||||
example a core may be the hierarchy block, and separated out of a
|
||||
multi-core SoC.
|
||||
example, a core may be the hierarchy block separated out of a multi-core
|
||||
SoC design.
|
||||
|
||||
Verilator is run in hierarchical mode on the whole SoC. Verilator will
|
||||
make two models, one for the CPU hierarchy block, and one for the SoC. The
|
||||
make two models, one for the CPU hierarchy block and one for the SoC. The
|
||||
Verilated code for the SoC will automatically call the CPU Verilated model.
|
||||
|
||||
The current hierarchical Verilation is based on :vlopt:`--lib-create`. Each
|
||||
@@ -78,16 +78,16 @@ blocks will see a tiny wrapper generated by :vlopt:`--lib-create`.
|
||||
Usage
|
||||
-----
|
||||
|
||||
Users need to mark one or more moderate size module as hierarchy block(s).
|
||||
Users need to mark one or more moderate-size modules as hierarchy block(s).
|
||||
There are two ways to mark a module:
|
||||
|
||||
* Write :option:`/*verilator&32;hier_block*/` metacomment in HDL code.
|
||||
|
||||
* Add a :option:`hier_block` line in a the :ref:`Configuration Files`.
|
||||
* Add a :option:`hier_block` line in the :ref:`Configuration Files`.
|
||||
|
||||
Then pass the :vlopt:`--hierarchical` option to Verilator
|
||||
Then pass the :vlopt:`--hierarchical` option to Verilator.
|
||||
|
||||
Compilation is the same as when not using hierarchical mode.
|
||||
The compilation is the same as when not using hierarchical mode.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
@@ -97,21 +97,22 @@ Compilation is the same as when not using hierarchical mode.
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
Hierarchy blocks have some limitations including:
|
||||
Hierarchy blocks have some limitations, including:
|
||||
|
||||
* The hierarchy block cannot be accessed using dot (.) from upper module(s)
|
||||
or other hierarchy blocks.
|
||||
* The hierarchy block cannot be accessed using dot (.) from the upper
|
||||
module(s) or other hierarchy blocks.
|
||||
|
||||
* Signals in the block cannot be traced.
|
||||
|
||||
* Modport cannot be used at the hierarchical block boundary.
|
||||
|
||||
* The simulation speed is likely to not be as fast as flat Verilation, in
|
||||
which all modules are globally scheduled.
|
||||
* The simulation speed is likely not as fast as flat Verilation, in which
|
||||
all modules are globally scheduled.
|
||||
|
||||
* Generated clocks may not work correctly if they are generated in the
|
||||
hierarchical model and pass up into another hierarchical model or the top
|
||||
module.
|
||||
* Generated clocks may not work correctly if generated in the hierarchical
|
||||
model and passed into another hierarchical model or the top module.
|
||||
|
||||
* Delays are not allowed in hierarchy blocks.
|
||||
|
||||
But, the following usage is supported:
|
||||
|
||||
@@ -128,8 +129,8 @@ Overlapping Verilation and Compilation
|
||||
--------------------------------------
|
||||
|
||||
Verilator needs to run 2 + *N* times in hierarchical Verilation, where *N*
|
||||
is the number of hierarchy blocks. One of the two is for the top module
|
||||
which refers wrappers of all other hierarchy blocks. The second one of the
|
||||
is the number of hierarchy blocks. One of the two is for the top module,
|
||||
which refers to the wrappers of all other hierarchy blocks. The second of the
|
||||
two is the initial run that searches modules marked with
|
||||
:option:`/*verilator&32;hier_block*/` metacomment and creates a plan and
|
||||
write in :file:`{prefix}_hier.mk`. This initial run internally invokes
|
||||
@@ -151,19 +152,19 @@ Verilator supports cross-compiling Verilated code. This is generally used
|
||||
to run Verilator on a Linux system and produce C++ code that is then compiled
|
||||
on Windows.
|
||||
|
||||
Cross compilation involves up to three different OSes. The build system is
|
||||
where you configured and compiled Verilator, the host system where you run
|
||||
Verilator, and the target system where you compile the Verilated code and
|
||||
run the simulation.
|
||||
Cross-compilation involves up to three different OSes. The build system is
|
||||
where you configure and compile Verilator, the host system is where you run
|
||||
Verilator, and the target system is where you compile the Verilated code
|
||||
and run the simulation.
|
||||
|
||||
Currently, Verilator requires the build and host system type to be the
|
||||
Verilator requires the build and host system types to be the
|
||||
same, though the target system type may be different. To support this,
|
||||
:command:`./configure` and make Verilator on the build system. Then, run
|
||||
Verilator on the host system. Finally, the output of Verilator may be
|
||||
compiled on the different target system.
|
||||
|
||||
To support this, none of the files that Verilator produces will reference
|
||||
any configure generated build-system specific files, such as
|
||||
any configure-generated build-system-specific files, such as
|
||||
:file:`config.h` (which is renamed in Verilator to :file:`config_build.h`
|
||||
to reduce confusion.) The disadvantage of this approach is that
|
||||
:file:`include/verilatedos.h` must self-detect the requirements of the
|
||||
@@ -181,41 +182,29 @@ Multithreading
|
||||
|
||||
Verilator supports multithreaded simulation models.
|
||||
|
||||
With :vlopt:`--no-threads`, the default, the model is not thread safe, and
|
||||
any use of more than one thread calling into one or even different
|
||||
Verilated models may result in unpredictable behavior. This gives the
|
||||
highest single thread performance.
|
||||
|
||||
With :vlopt:`--threads 1 <--threads>`, the generated model is single
|
||||
threaded, however the support libraries are multithread safe. This allows
|
||||
different instantiations of model(s) to potentially each be run under a
|
||||
different thread. All threading is the responsibility of the user's C++
|
||||
testbench.
|
||||
With :vlopt:`--threads 1 <--threads>`, the generated model is
|
||||
single-threaded; however, the support libraries are multithread safe. This
|
||||
allows different instantiations of the model(s) to potentially each be run
|
||||
under a different thread. All threading is the responsibility of the user's
|
||||
C++ testbench.
|
||||
|
||||
With :vlopt:`--threads {N} <--threads>`, where N is at least 2, the
|
||||
generated model will be designed to run in parallel on N threads. The
|
||||
thread calling eval() provides one of those threads, and the generated
|
||||
model will create and manage the other N-1 threads. It's the client's
|
||||
responsibility not to oversubscribe the available CPU cores. Under CPU
|
||||
oversubscription, the Verilated model should not livelock nor deadlock,
|
||||
oversubscription, the Verilated model should not livelock nor deadlock;
|
||||
however, you can expect performance to be far worse than it would be with
|
||||
proper ratio of threads and CPU cores.
|
||||
|
||||
The remainder of this section describe behavior with :vlopt:`--threads 1
|
||||
<--threads>` or :vlopt:`--threads {N} <--threads>` (not
|
||||
:vlopt:`--no-threads`).
|
||||
|
||||
:code:`VL_THREADED` is defined in the C++ code when compiling a threaded
|
||||
Verilated module, causing the Verilated support classes become threadsafe.
|
||||
the proper ratio of threads and CPU cores.
|
||||
|
||||
The thread used for constructing a model must be the same thread that calls
|
||||
:code:`eval()` into the model, this is called the "eval thread". The thread
|
||||
used to perform certain global operations such as saving and tracing must
|
||||
be done by a "main thread". In most cases the eval thread and main thread
|
||||
:code:`eval()` into the model; this is called the "eval thread". The thread
|
||||
used to perform certain global operations, such as saving and tracing, must
|
||||
be done by a "main thread". In most cases, the eval thread and main thread
|
||||
are the same thread (i.e. the user's top C++ testbench runs on a single
|
||||
thread), but this is not required.
|
||||
|
||||
When making frequent use of DPI imported functions in a multi-threaded
|
||||
When making frequent use of DPI imported functions in a multithreaded
|
||||
model, it may be beneficial to performance to adjust the
|
||||
:vlopt:`--instr-count-dpi` option based on some experimentation. This
|
||||
influences the partitioning of the model by adjusting the assumed execution
|
||||
@@ -228,46 +217,46 @@ with :vlopt:`--threads`, and is executed on the same thread pool as the model.
|
||||
The :vlopt:`--trace-threads` options can be used with :vlopt:`--trace-fst`
|
||||
to offload FST tracing using multiple threads. If :vlopt:`--trace-threads` is
|
||||
given without :vlopt:`--threads`, then :vlopt:`--trace-threads` will imply
|
||||
:vlopt:`--threads 1 <--threads>`, i.e.: the support libraries will be
|
||||
:vlopt:`--threads 1 <--threads>`, i.e., the support libraries will be
|
||||
thread safe.
|
||||
|
||||
With :vlopt:`--trace-threads 0 <--trace-threads>`, trace dumps are produced
|
||||
on the main thread. This again gives the highest single thread performance.
|
||||
on the main thread. This again gives the highest single-thread performance.
|
||||
|
||||
With :vlopt:`--trace-threads {N} <--trace-threads>`, where N is at least 1,
|
||||
up to N additional threads will be created and managed by the trace files
|
||||
(e.g.: VerilatedFstC), to offload construction of the trace dump. The main
|
||||
(e.g., VerilatedFstC), to offload construction of the trace dump. The main
|
||||
thread will be released to proceed with execution as soon as possible, though
|
||||
some blocking of the main thread is still necessary while capturing the
|
||||
some main thread blocking is still necessary while capturing the
|
||||
trace. FST tracing can utilize up to 2 offload threads, so there is no use
|
||||
of setting :vlopt:`--trace-threads` higher than 2 at the moment.
|
||||
|
||||
When running a multithreaded model, the default Linux task scheduler often
|
||||
works against the model, by assuming threads are short lived, and thus
|
||||
often schedules threads using multiple hyperthreads within the same
|
||||
physical core. For best performance use the :command:`numactl` program to
|
||||
works against the model by assuming short-lived threads and thus
|
||||
it often schedules threads using multiple hyperthreads within the same
|
||||
physical core. For best performance, use the :command:`numactl` program to
|
||||
(when the threading count fits) select unique physical cores on the same
|
||||
socket. The same applies for :vlopt:`--trace-threads` as well.
|
||||
|
||||
As an example, if a model was Verilated with :vlopt:`--threads 4
|
||||
<--threads>`, we consult:
|
||||
As an example, if a model was Verilated with
|
||||
:vlopt:`--threads 4 <--threads>`, we consult:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
egrep 'processor|physical id|core id' /proc/cpuinfo
|
||||
|
||||
To select cores 0, 1, 2, and 3 that are all located on the same socket (0)
|
||||
but different physical cores. (Also useful is :command:`numactl
|
||||
--hardware`, or :command:`lscpu` but those doesn't show Hyperthreading
|
||||
cores.) Then we execute:
|
||||
but have different physical cores. (Also useful is
|
||||
:command:`numactl --hardware`, or :command:`lscpu`, but those don't show
|
||||
hyperthreading cores.) Then we execute:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
numactl -m 0 -C 0,1,2,3 -- verilated_executable_name
|
||||
|
||||
This will limit memory to socket 0, and threads to cores 0, 1, 2, 3,
|
||||
(presumably on socket 0) optimizing performance. Of course this must be
|
||||
adjusted if you want another simulator using e.g. socket 1, or if you
|
||||
(presumably on socket 0), optimizing performance. Of course, this must be
|
||||
adjusted if you want another simulator to use, e.g., socket 1, or if you
|
||||
Verilated with a different number of threads. To see what CPUs are
|
||||
actually used, use :vlopt:`--prof-exec`.
|
||||
|
||||
@@ -275,19 +264,19 @@ actually used, use :vlopt:`--prof-exec`.
|
||||
Multithreaded Verilog and Library Support
|
||||
-----------------------------------------
|
||||
|
||||
$display/$stop/$finish are delayed until the end of an eval() call in order
|
||||
$display/$stop/$finish are delayed until the end of an eval() call
|
||||
to maintain ordering between threads. This may result in additional tasks
|
||||
completing after the $stop or $finish.
|
||||
|
||||
If using :vlopt:`--coverage`, the coverage routines are fully thread safe.
|
||||
If using :vlopt:`--coverage`, the coverage routines are fully thread-safe.
|
||||
|
||||
If using the DPI, Verilator assumes pure DPI imports are thread safe,
|
||||
If using the DPI, Verilator assumes pure DPI imports are thread-safe,
|
||||
balancing performance versus safety. See :vlopt:`--threads-dpi`.
|
||||
|
||||
If using :vlopt:`--savable`, the save/restore classes are not multithreaded
|
||||
and must be called only by the eval thread.
|
||||
|
||||
If using :vlopt:`--sc`, the SystemC kernel is not thread safe, therefore
|
||||
If using :vlopt:`--sc`, the SystemC kernel is not thread-safe; therefore,
|
||||
the eval thread and main thread must be the same.
|
||||
|
||||
If using :vlopt:`--trace`, the tracing classes must be constructed and
|
||||
@@ -307,8 +296,8 @@ Verilator defaults to creating GNU Make makefiles for the model. Verilator
|
||||
will call make automatically when the :vlopt:'--build' option is used.
|
||||
|
||||
If calling Verilator from a makefile, the :vlopt:'-MMD' option will create
|
||||
a dependency file which will allow Make to only run Verilator if input
|
||||
Verilog files change.
|
||||
a dependency file, allowing Make to only run Verilator if input Verilog
|
||||
files change.
|
||||
|
||||
.. _CMake:
|
||||
|
||||
@@ -317,8 +306,8 @@ CMake
|
||||
|
||||
Verilator can be run using CMake, which takes care of both running
|
||||
Verilator and compiling the output. There is a CMake example in the
|
||||
examples/ directory. The following is a minimal CMakeLists.txt that would
|
||||
build the code listed in :ref:`Example C++ Execution`
|
||||
:file:`examples/` directory. The following is a minimal CMakeLists.txt that
|
||||
would build the code listed in :ref:`Example C++ Execution`
|
||||
|
||||
.. code-block:: CMake
|
||||
|
||||
@@ -330,8 +319,8 @@ build the code listed in :ref:`Example C++ Execution`
|
||||
:code:`find_package` will automatically find an installed copy of
|
||||
Verilator, or use a local build if VERILATOR_ROOT is set.
|
||||
|
||||
It is recommended to use CMake >= 3.12 and the Ninja generator, though
|
||||
other combinations should work. To build with CMake, change to the folder
|
||||
Using CMake >= 3.12 and the Ninja generator is recommended, though other
|
||||
combinations should work. To build with CMake, change to the folder
|
||||
containing CMakeLists.txt and run:
|
||||
|
||||
.. code-block:: bash
|
||||
@@ -350,14 +339,14 @@ Or to build with your system default generator:
|
||||
cmake ..
|
||||
cmake --build .
|
||||
|
||||
If you're building the example you should have an executable to run:
|
||||
If you're building the example, you should have an executable to run:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
./Vour
|
||||
|
||||
The package sets the CMake variables verilator_FOUND, VERILATOR_ROOT and
|
||||
VERILATOR_BIN to the appropriate values, and also creates a verilate()
|
||||
The package sets the CMake variables verilator_FOUND, VERILATOR_ROOT,
|
||||
and VERILATOR_BIN to the appropriate values and creates a verilate()
|
||||
function. verilate() will automatically create custom commands to run
|
||||
Verilator and add the generated C++ sources to the target specified.
|
||||
|
||||
@@ -372,14 +361,14 @@ Verilate in CMake
|
||||
[OPT_GLOBAL ..] [DIRECTORY dir] [THREADS num]
|
||||
[TRACE_THREADS num] [VERILATOR_ARGS ...])
|
||||
|
||||
Lowercase and ... should be replaced with arguments, the uppercase parts
|
||||
delimit the arguments and can be passed in any order, or left out entirely
|
||||
Lowercase and ... should be replaced with arguments; the uppercase parts
|
||||
delimit the arguments and can be passed in any order or left out entirely
|
||||
if optional.
|
||||
|
||||
verilate(target ...) can be called multiple times to add other Verilog
|
||||
modules to an executable or library target.
|
||||
|
||||
When generating Verilated SystemC sources, you should also include the
|
||||
When generating Verilated SystemC sources, you should list the
|
||||
SystemC include directories and link to the SystemC libraries.
|
||||
|
||||
.. describe:: target
|
||||
@@ -389,7 +378,7 @@ SystemC include directories and link to the SystemC libraries.
|
||||
.. describe:: COVERAGE
|
||||
|
||||
Optional. Enables coverage if present, equivalent to "VERILATOR_ARGS
|
||||
--coverage"
|
||||
--coverage".
|
||||
|
||||
.. describe:: DIRECTORY
|
||||
|
||||
@@ -417,22 +406,22 @@ SystemC include directories and link to the SystemC libraries.
|
||||
.. describe:: PREFIX
|
||||
|
||||
Optional. Sets the Verilator output prefix. Defaults to the name of the
|
||||
first source file with a "V" prepended. Must be unique in each call to
|
||||
verilate(), so this is necessary if you build a module multiple times
|
||||
with different parameters. Must be a valid C++ identifier, i.e. contains
|
||||
no white space and only characters A-Z, a-z, 0-9 or _.
|
||||
first source file with a "V" prepended. It must be unique in each call
|
||||
to verilate(), so this is necessary if you build a module multiple times
|
||||
with different parameters. It must be a valid C++ identifier, i.e., it
|
||||
contains no white space and only characters A-Z, a-z, 0-9 or _.
|
||||
|
||||
.. describe:: SOURCES
|
||||
|
||||
List of Verilog files to Verilate. Must have at least one file.
|
||||
List of Verilog files to Verilate. You must provide at least one file.
|
||||
|
||||
.. describe:: SYSTEMC
|
||||
|
||||
Optional. Enables SystemC mode, defaults to C++ if not specified.
|
||||
|
||||
When using Accellera's SystemC with CMake support, a CMake target is
|
||||
available that simplifies the SystemC steps. This will only work if the
|
||||
SystemC installation can be found by CMake. This can be configured by
|
||||
available that simplifies the SystemC steps. This will only work if
|
||||
CMake can find the SystemC installation, and this can be configured by
|
||||
setting the CMAKE_PREFIX_PATH variable during CMake configuration.
|
||||
|
||||
Don't forget to set the same C++ standard for the Verilated sources as
|
||||
@@ -441,12 +430,11 @@ SystemC include directories and link to the SystemC libraries.
|
||||
|
||||
.. describe:: THREADS
|
||||
|
||||
Optional. Generated a multi-threaded model, same as "--threads".
|
||||
Optional. Enable a multithreaded model; see :vlopt:`--threads`.
|
||||
|
||||
.. describe:: TRACE_THREADS
|
||||
|
||||
Optional. Generated multi-threaded FST trace dumping, same as
|
||||
"--trace-threads".
|
||||
Optional. Enable multithreaded FST trace; see :vlopt:`--trace-threads`.
|
||||
|
||||
.. describe:: TOP_MODULE
|
||||
|
||||
@@ -466,7 +454,7 @@ SystemC include directories and link to the SystemC libraries.
|
||||
.. describe:: VERILATOR_ARGS
|
||||
|
||||
Optional. Extra arguments to Verilator. Do not specify :vlopt:`--Mdir`
|
||||
or :vlopt:`--prefix` here, use DIRECTORY or PREFIX.
|
||||
or :vlopt:`--prefix` here; use DIRECTORY or PREFIX.
|
||||
|
||||
|
||||
SystemC Link in CMake
|
||||
|
||||
+437
-328
File diff suppressed because it is too large
Load Diff
+758
-94
File diff suppressed because it is too large
Load Diff
+31
-1
@@ -7,12 +7,14 @@ Ami
|
||||
Amir
|
||||
Anastasiadis
|
||||
Anikin
|
||||
Antmicro
|
||||
Antonin
|
||||
Antwerpen
|
||||
Arasanipalai
|
||||
Arjen
|
||||
Asciidoc
|
||||
Ashutosh
|
||||
Ast
|
||||
Atmel
|
||||
Aurelien
|
||||
Bagri
|
||||
@@ -43,6 +45,7 @@ Cochrane
|
||||
Cuan
|
||||
Cygwin
|
||||
DErrico
|
||||
DFG
|
||||
Da
|
||||
Danilo
|
||||
Dannoritzer
|
||||
@@ -108,8 +111,10 @@ Goessling
|
||||
Gonnen
|
||||
Goorah
|
||||
Gossner
|
||||
Graphviz
|
||||
Graybeal
|
||||
Grobman
|
||||
Grulfen
|
||||
Gunter
|
||||
Guo
|
||||
Hao
|
||||
@@ -131,6 +136,7 @@ Iles
|
||||
Inlines
|
||||
Inout
|
||||
Iru
|
||||
Iyer
|
||||
Iztok
|
||||
Jacko
|
||||
Jae
|
||||
@@ -157,6 +163,7 @@ Karge
|
||||
Karlsson
|
||||
Katz
|
||||
Katzman
|
||||
Kelin
|
||||
Keren
|
||||
Keyi
|
||||
Kimmitt
|
||||
@@ -219,6 +226,7 @@ Nalbantis
|
||||
Narayan
|
||||
Nauticus
|
||||
Newgard
|
||||
Nigam
|
||||
Nikana
|
||||
Niranjan
|
||||
Nitza
|
||||
@@ -233,6 +241,7 @@ Patricio
|
||||
Petr
|
||||
Piechotka
|
||||
Piersall
|
||||
Platzer
|
||||
Plunkett
|
||||
Popolon
|
||||
Popov
|
||||
@@ -247,6 +256,7 @@ Pullup
|
||||
Pulver
|
||||
Puri
|
||||
Questa
|
||||
Rachit
|
||||
Ralf
|
||||
Rapp
|
||||
Redhat
|
||||
@@ -340,6 +350,7 @@ Verilating
|
||||
Verilation
|
||||
Verilator
|
||||
Verilog
|
||||
Vighnesh
|
||||
Viktor
|
||||
Vm
|
||||
Vukobratovic
|
||||
@@ -376,6 +387,8 @@ agrobman
|
||||
ahouska
|
||||
al
|
||||
ala
|
||||
alejandro
|
||||
algrobman
|
||||
andit
|
||||
ar
|
||||
architected
|
||||
@@ -397,7 +410,7 @@ bbox
|
||||
benchmarking
|
||||
biguint
|
||||
biops
|
||||
bitOpTree
|
||||
bisonpre
|
||||
bitOpTree
|
||||
bitop
|
||||
bitstoreal
|
||||
@@ -413,6 +426,7 @@ callValueCbs
|
||||
casex
|
||||
casez
|
||||
casted
|
||||
castro
|
||||
cb
|
||||
ccache
|
||||
ccall
|
||||
@@ -441,6 +455,7 @@ const
|
||||
constexpr
|
||||
constpool
|
||||
coredump
|
||||
coroutine
|
||||
countbits
|
||||
countones
|
||||
cout
|
||||
@@ -452,6 +467,7 @@ cutable
|
||||
cygwin
|
||||
dM
|
||||
da
|
||||
danbone
|
||||
dat
|
||||
datadir
|
||||
datafiles
|
||||
@@ -463,6 +479,7 @@ defenv
|
||||
defname
|
||||
defparam
|
||||
demangling
|
||||
dep
|
||||
der
|
||||
dereference
|
||||
desassign
|
||||
@@ -480,6 +497,7 @@ dsvf
|
||||
dtor
|
||||
dumpall
|
||||
dumpfile
|
||||
dumpi
|
||||
dumplimit
|
||||
dumpoff
|
||||
dumpon
|
||||
@@ -537,6 +555,7 @@ filesystem
|
||||
filt
|
||||
flto
|
||||
flushCall
|
||||
fno
|
||||
fopen
|
||||
forceable
|
||||
foreach
|
||||
@@ -577,6 +596,7 @@ hierCMakeArgs
|
||||
hierMkArgs
|
||||
hierVer
|
||||
hx
|
||||
hyperthreading
|
||||
hyperthreads
|
||||
icecream
|
||||
idmap
|
||||
@@ -587,6 +607,7 @@ ifndef
|
||||
impot
|
||||
incdir
|
||||
includer
|
||||
incrementing
|
||||
inferfaces
|
||||
inhibitSim
|
||||
initarray
|
||||
@@ -600,6 +621,7 @@ inouts
|
||||
inserted
|
||||
instantiation
|
||||
instantiations
|
||||
intra
|
||||
iostream
|
||||
ish
|
||||
isunbounded
|
||||
@@ -626,6 +648,7 @@ localparams
|
||||
localtime
|
||||
logicals
|
||||
longint
|
||||
lossy
|
||||
lsb
|
||||
lvalue
|
||||
lxt
|
||||
@@ -635,6 +658,7 @@ makefiles
|
||||
manpages
|
||||
metacomment
|
||||
metacomments
|
||||
miree
|
||||
mis
|
||||
misconnected
|
||||
misconversion
|
||||
@@ -643,6 +667,7 @@ mk
|
||||
mno
|
||||
modport
|
||||
modports
|
||||
mpb
|
||||
msg
|
||||
msvc
|
||||
mtask
|
||||
@@ -682,6 +707,7 @@ nullptr
|
||||
onehot
|
||||
ooo
|
||||
oprofile
|
||||
ortegon
|
||||
oversubscription
|
||||
parallelized
|
||||
param
|
||||
@@ -725,6 +751,7 @@ profiler
|
||||
prototyptes
|
||||
ps
|
||||
pthread
|
||||
ptr
|
||||
pulldown
|
||||
pulldowns
|
||||
pullup
|
||||
@@ -733,6 +760,7 @@ pwd
|
||||
qrq
|
||||
radix
|
||||
randc
|
||||
randcase
|
||||
rarr
|
||||
rdtsc
|
||||
reStructuredText
|
||||
@@ -750,6 +778,7 @@ reloop
|
||||
resetall
|
||||
respecified
|
||||
rodata
|
||||
rolloverSize
|
||||
rr
|
||||
rst
|
||||
runtime
|
||||
@@ -764,6 +793,7 @@ seg
|
||||
setuphold
|
||||
sformat
|
||||
sformatf
|
||||
shareefj
|
||||
shortint
|
||||
shortreal
|
||||
signame
|
||||
|
||||
@@ -37,5 +37,4 @@ PREDEFINED = \
|
||||
"VL_NOT_FINAL=" \
|
||||
"VL_PURE=" \
|
||||
"VL_REQUIRES()=" \
|
||||
"VL_THREAD_LOCAL=" \
|
||||
"__restrict=" \
|
||||
|
||||
@@ -39,30 +39,12 @@ ifneq ($(CMAKE_GT_3_8),true)
|
||||
TARGET := oldcmake
|
||||
else
|
||||
|
||||
# Test existence of SYSTEMC_INCLUDE and SYSTEMC_LIBDIR environment variabless
|
||||
ifneq (,$(SYSTEMC_INCLUDE))
|
||||
ifneq (,${SYSTEMC_LIBDIR})
|
||||
SYSTEMC_SET := true
|
||||
endif
|
||||
endif
|
||||
|
||||
# Test existence of SYSTEMC_ROOT environment variable
|
||||
ifneq (SYSTEMC_SET, true)
|
||||
ifneq (,${SYSTEMC_ROOT})
|
||||
SYSTEMC_SET := true
|
||||
endif
|
||||
endif
|
||||
|
||||
# Test existence of SYSTEMC environment variable
|
||||
ifneq (SYSTEMC_SET, true)
|
||||
ifneq (,${SYSTEMC})
|
||||
SYSTEMC_SET := true
|
||||
endif
|
||||
endif
|
||||
# Check if SC exists via a verilator call (empty if not)
|
||||
SYSTEMC_EXISTS := $(shell $(VERILATOR) --get-supported SYSTEMC)
|
||||
|
||||
# Test whether SystemC is installed with CMake support
|
||||
# This will print a CMake error about processing arguments that can (currently) be ignored.
|
||||
ifneq (SYSTEMC_SET, true)
|
||||
ifneq (,$(SYSTEMC_EXISTS))
|
||||
FINDSC := $(shell mkdir -p build && cd build && cmake --find-package -DNAME=SystemCLanguage -DCMAKE_USE_PTHREADS_INIT=ON -DCOMPILER_ID=GNU -DLANGUAGE=CXX -DMODE=EXIST -DThreads_FOUND=ON)
|
||||
ifneq (,$(findstring SystemCLanguage found,$(FINDSC)))
|
||||
SYSTEMC_SET := true
|
||||
|
||||
@@ -39,30 +39,12 @@ ifneq ($(CMAKE_GT_3_8),true)
|
||||
TARGET := oldcmake
|
||||
else
|
||||
|
||||
# Test existence of SYSTEMC_INCLUDE and SYSTEMC_LIBDIR environment variabless
|
||||
ifneq (,$(SYSTEMC_INCLUDE))
|
||||
ifneq (,${SYSTEMC_LIBDIR})
|
||||
SYSTEMC_SET := true
|
||||
endif
|
||||
endif
|
||||
|
||||
# Test existence of SYSTEMC_ROOT environment variable
|
||||
ifneq (SYSTEMC_SET, true)
|
||||
ifneq (,${SYSTEMC_ROOT})
|
||||
SYSTEMC_SET := true
|
||||
endif
|
||||
endif
|
||||
|
||||
# Test existence of SYSTEMC environment variable
|
||||
ifneq (SYSTEMC_SET, true)
|
||||
ifneq (,${SYSTEMC})
|
||||
SYSTEMC_SET := true
|
||||
endif
|
||||
endif
|
||||
# Check if SC exists via a verilator call (empty if not)
|
||||
SYSTEMC_EXISTS := $(shell $(VERILATOR) --get-supported SYSTEMC)
|
||||
|
||||
# Test whether SystemC is installed with CMake support
|
||||
# This will print a CMake error about processing arguments that can (currently) be ignored.
|
||||
ifneq (SYSTEMC_SET, true)
|
||||
ifneq (,$(SYSTEMC_EXISTS))
|
||||
FINDSC := $(shell mkdir -p build && cd build && cmake --find-package -DNAME=SystemCLanguage -DCMAKE_USE_PTHREADS_INIT=ON -DCOMPILER_ID=GNU -DLANGUAGE=CXX -DMODE=EXIST -DThreads_FOUND=ON)
|
||||
ifneq (,$(findstring SystemCLanguage found,$(FINDSC)))
|
||||
SYSTEMC_SET := true
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
*.dmp
|
||||
*.log
|
||||
*.csrc
|
||||
*.vcd
|
||||
obj_*
|
||||
logs
|
||||
@@ -0,0 +1,49 @@
|
||||
######################################################################
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: Small Makefile
|
||||
#
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
# any use, without warranty, 2020 by Wilson Snyder.
|
||||
# SPDX-License-Identifier: CC0-1.0
|
||||
#
|
||||
######################################################################
|
||||
# Check for sanity to avoid later confusion
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
|
||||
# This is intended to be a minimal example. Before copying this to start a
|
||||
# real project, it is better to start with a more complete example,
|
||||
# e.g. examples/make_tracing_c.
|
||||
|
||||
# If $VERILATOR_ROOT isn't in the environment, we assume it is part of a
|
||||
# package install, and verilator is in your path. Otherwise find the
|
||||
# binary relative to $VERILATOR_ROOT (such as when inside the git sources).
|
||||
ifeq ($(VERILATOR_ROOT),)
|
||||
VERILATOR = verilator
|
||||
else
|
||||
export VERILATOR_ROOT
|
||||
VERILATOR = $(VERILATOR_ROOT)/bin/verilator
|
||||
endif
|
||||
|
||||
default:
|
||||
@echo "-- Verilator hello-world simple binary example"
|
||||
@echo "-- VERILATE & BUILD --------"
|
||||
$(VERILATOR) --binary -j 0 top.v
|
||||
@echo "-- RUN ---------------------"
|
||||
obj_dir/Vtop
|
||||
@echo "-- DONE --------------------"
|
||||
@echo "Note: Once this example is understood, see examples/make_hello_c."
|
||||
@echo "Note: See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
######################################################################
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_dir *.log *.dmp *.vpd core
|
||||
@@ -0,0 +1,14 @@
|
||||
// DESCRIPTION: Verilator: Verilog example module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2017 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
// See also https://verilator.org/guide/latest/examples.html"
|
||||
|
||||
module top;
|
||||
initial begin
|
||||
$display("Hello World!");
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
@@ -11,21 +11,25 @@
|
||||
// Include model header, generated from Verilating "top.v"
|
||||
#include "Vtop.h"
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
int main(int argc, char** argv) {
|
||||
// See a similar example walkthrough in the verilator manpage.
|
||||
|
||||
// This is intended to be a minimal example. Before copying this to start a
|
||||
// real project, it is better to start with a more complete example,
|
||||
// e.g. examples/c_tracing.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (false && argc && argv && env) {}
|
||||
// Construct a VerilatedContext to hold simulation time, etc.
|
||||
VerilatedContext* contextp = new VerilatedContext;
|
||||
|
||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||
// This needs to be called before you create any model
|
||||
contextp->commandArgs(argc, argv);
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||
Vtop* top = new Vtop;
|
||||
Vtop* top = new Vtop{contextp};
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
while (!contextp->gotFinish()) {
|
||||
|
||||
// Evaluate model
|
||||
top->eval();
|
||||
|
||||
@@ -33,7 +33,7 @@ VERILATOR = $(VERILATOR_ROOT)/bin/verilator
|
||||
endif
|
||||
|
||||
# Check if SC exists via a verilator call (empty if not)
|
||||
SYSTEMC_EXISTS := $(shell $(VERILATOR) --getenv SYSTEMC_INCLUDE)
|
||||
SYSTEMC_EXISTS := $(shell $(VERILATOR) --get-supported SYSTEMC)
|
||||
|
||||
ifneq ($(SYSTEMC_EXISTS),)
|
||||
default: run
|
||||
|
||||
@@ -22,12 +22,13 @@ int sc_main(int argc, char* argv[]) {
|
||||
// real project, it is better to start with a more complete example,
|
||||
// e.g. examples/c_tracing.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (false && argc && argv) {}
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||
Vtop* top = new Vtop{"top"};
|
||||
|
||||
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
|
||||
// This needs to be called before you create any model
|
||||
Verilated::commandArgs(argc, argv);
|
||||
|
||||
// Initialize SC model
|
||||
sc_start(1, SC_NS);
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
#include <verilated_vcd_c.h>
|
||||
#endif
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
if (false && argc && argv && env) {}
|
||||
int main(int argc, char** argv) {
|
||||
if (false && argc && argv) {}
|
||||
|
||||
// Construct context to hold simulation time, etc
|
||||
VerilatedContext* contextp = new VerilatedContext;
|
||||
@@ -32,7 +32,7 @@ int main(int argc, char** argv, char** env) {
|
||||
// When tracing, the contents of the secret module will not be seen
|
||||
VerilatedVcdC* tfp = nullptr;
|
||||
const char* flag = contextp->commandArgsPlusMatch("trace");
|
||||
if (flag && 0 == strcmp(flag, "+trace")) {
|
||||
if (flag && 0 == std::strcmp(flag, "+trace")) {
|
||||
contextp->traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
|
||||
tfp = new VerilatedVcdC;
|
||||
|
||||
@@ -17,11 +17,11 @@
|
||||
// Legacy function required only so linking works on Cygwin and MSVC++
|
||||
double sc_time_stamp() { return 0; }
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
int main(int argc, char** argv) {
|
||||
// This is a more complicated example, please also see the simpler examples/make_hello_c.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (false && argc && argv && env) {}
|
||||
if (false && argc && argv) {}
|
||||
|
||||
// Create logs/ directory in case we have traces to put under it
|
||||
Verilated::mkdir("logs");
|
||||
|
||||
@@ -55,7 +55,7 @@ VERILATOR_FLAGS += --coverage
|
||||
VERILATOR_INPUT = -f input.vc top.v sc_main.cpp
|
||||
|
||||
# Check if SC exists via a verilator call (empty if not)
|
||||
SYSTEMC_EXISTS := $(shell $(VERILATOR) --getenv SYSTEMC_INCLUDE)
|
||||
SYSTEMC_EXISTS := $(shell $(VERILATOR) --get-supported SYSTEMC)
|
||||
|
||||
######################################################################
|
||||
|
||||
|
||||
@@ -82,15 +82,15 @@ int sc_main(int argc, char* argv[]) {
|
||||
|
||||
// You must do one evaluation before enabling waves, in order to allow
|
||||
// SystemC to interconnect everything for testing.
|
||||
sc_start(1, SC_NS);
|
||||
sc_start(SC_ZERO_TIME);
|
||||
|
||||
#if VM_TRACE
|
||||
// If verilator was invoked with --trace argument,
|
||||
// and if at run time passed the +trace argument, turn on tracing
|
||||
VerilatedVcdSc* tfp = nullptr;
|
||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||
if (flag && 0 == strcmp(flag, "+trace")) {
|
||||
cout << "Enabling waves into logs/vlt_dump.vcd...\n";
|
||||
if (flag && 0 == std::strcmp(flag, "+trace")) {
|
||||
std::cout << "Enabling waves into logs/vlt_dump.vcd...\n";
|
||||
tfp = new VerilatedVcdSc;
|
||||
top->trace(tfp, 99); // Trace 99 levels of hierarchy
|
||||
Verilated::mkdir("logs");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- Python -*- See copyright, etc below
|
||||
# pylint: disable=C0114,C0115,R0903
|
||||
# pylint: disable=C0114,C0115,C0209,R0903
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
@@ -16,27 +16,26 @@ from shutil import copy2
|
||||
|
||||
|
||||
class VlFileCopy:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
verilator_args, # presently all verilator options are passed-thru
|
||||
# ideally this script would check against options mentioned in help
|
||||
debug=0,
|
||||
output_dir='copied'): # directory name we output file uses
|
||||
self,
|
||||
verilator_args, # presently all verilator options are passed-thru
|
||||
debug=0,
|
||||
output_dir='copied'): # directory name we output file uses
|
||||
|
||||
self.debug = debug
|
||||
|
||||
xml_temp = tempfile.NamedTemporaryFile()
|
||||
|
||||
vargs = [
|
||||
'--xml-output',
|
||||
xml_temp.name,
|
||||
'--bbox-sys', # Parse some stuff can't translate
|
||||
'--bbox-unsup',
|
||||
'--prefix vlxml'
|
||||
] # So we know name of .xml output
|
||||
vargs += verilator_args
|
||||
self.run_verilator(vargs)
|
||||
self.tree = ET.parse(xml_temp.name)
|
||||
with tempfile.NamedTemporaryFile() as xml_temp:
|
||||
vargs = [
|
||||
'--xml-output',
|
||||
xml_temp.name,
|
||||
'--bbox-sys', # Parse some stuff can't translate
|
||||
'--bbox-unsup',
|
||||
'--prefix vlxml'
|
||||
] # So we know name of .xml output
|
||||
vargs += verilator_args
|
||||
self.run_verilator(vargs)
|
||||
self.tree = ET.parse(xml_temp.name)
|
||||
|
||||
os.makedirs(output_dir, 0o777, True)
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- Python -*- See copyright, etc below
|
||||
# pylint: disable=C0103,C0114,C0115,C0115,C0116,R0914
|
||||
# pylint: disable=C0103,C0114,C0115,C0115,C0116,C0209,R0914
|
||||
######################################################################
|
||||
|
||||
import argparse
|
||||
@@ -14,30 +14,29 @@ import xml.etree.ElementTree as ET
|
||||
|
||||
|
||||
class VlHierGraph:
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
verilator_args, # presently all verilator options are passed-thru
|
||||
# ideally this script would check against options mentioned in help
|
||||
debug=0,
|
||||
output_filename='graph.dot'): # output filename
|
||||
self,
|
||||
verilator_args, # presently all verilator options are passed-thru
|
||||
debug=0,
|
||||
output_filename='graph.dot'): # output filename
|
||||
self.debug = debug
|
||||
self.next_vertex_number = 0
|
||||
self.name_to_number = {}
|
||||
|
||||
xml_temp = tempfile.NamedTemporaryFile()
|
||||
with tempfile.NamedTemporaryFile() as xml_temp:
|
||||
vargs = [
|
||||
'--xml-output',
|
||||
xml_temp.name,
|
||||
'--bbox-sys', # Parse some stuff can't translate
|
||||
'--bbox-unsup',
|
||||
'--prefix vlxml'
|
||||
] # So we know name of .xml output
|
||||
vargs += verilator_args
|
||||
self.run_verilator(vargs)
|
||||
self.tree = ET.parse(xml_temp.name)
|
||||
|
||||
vargs = [
|
||||
'--xml-output',
|
||||
xml_temp.name,
|
||||
'--bbox-sys', # Parse some stuff can't translate
|
||||
'--bbox-unsup',
|
||||
'--prefix vlxml'
|
||||
] # So we know name of .xml output
|
||||
vargs += verilator_args
|
||||
self.run_verilator(vargs)
|
||||
self.tree = ET.parse(xml_temp.name)
|
||||
|
||||
with open(output_filename, "w") as fh:
|
||||
with open(output_filename, "w", encoding="utf8") as fh:
|
||||
# For more serious purposes, use the python graphviz package instead
|
||||
fh.write("digraph {\n")
|
||||
fh.write(" dpi=300;\n")
|
||||
|
||||
+50
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2009-2018 Tony Bybell.
|
||||
* Copyright (c) 2009-2023 Tony Bybell.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
@@ -140,7 +140,7 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3
|
||||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__)
|
||||
#if defined(FST_MACOSX) || defined(__MINGW32__) || defined(__OpenBSD__) || defined(__FreeBSD__) || defined(__NetBSD__)
|
||||
#define FST_UNBUFFERED_IO
|
||||
#endif
|
||||
|
||||
@@ -4130,26 +4130,35 @@ if(xc->do_rewind)
|
||||
if(!(isfeof=feof(xc->fh)))
|
||||
{
|
||||
int tag = fgetc(xc->fh);
|
||||
int cl;
|
||||
switch(tag)
|
||||
{
|
||||
case FST_ST_VCD_SCOPE:
|
||||
xc->hier.htyp = FST_HT_SCOPE;
|
||||
xc->hier.u.scope.typ = fgetc(xc->fh);
|
||||
xc->hier.u.scope.name = pnt = xc->str_scope_nam;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
*(pnt++) = ch;
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* scopename */
|
||||
*pnt = 0;
|
||||
xc->hier.u.scope.name_length = pnt - xc->hier.u.scope.name;
|
||||
pnt[cl] = 0;
|
||||
xc->hier.u.scope.name_length = cl;
|
||||
|
||||
xc->hier.u.scope.component = pnt = xc->str_scope_comp;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
*(pnt++) = ch;
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* scopecomp */
|
||||
*pnt = 0;
|
||||
xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component;
|
||||
pnt[cl] = 0;
|
||||
xc->hier.u.scope.component_length = cl;
|
||||
break;
|
||||
|
||||
case FST_ST_VCD_UPSCOPE:
|
||||
@@ -4161,12 +4170,16 @@ if(!(isfeof=feof(xc->fh)))
|
||||
xc->hier.u.attr.typ = fgetc(xc->fh);
|
||||
xc->hier.u.attr.subtype = fgetc(xc->fh);
|
||||
xc->hier.u.attr.name = pnt = xc->str_scope_nam;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
*(pnt++) = ch;
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* scopename */
|
||||
*pnt = 0;
|
||||
xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name;
|
||||
pnt[cl] = 0;
|
||||
xc->hier.u.attr.name_length = cl;
|
||||
|
||||
xc->hier.u.attr.arg = fstReaderVarint64(xc->fh);
|
||||
|
||||
@@ -4221,12 +4234,16 @@ if(!(isfeof=feof(xc->fh)))
|
||||
xc->hier.u.var.typ = tag;
|
||||
xc->hier.u.var.direction = fgetc(xc->fh);
|
||||
xc->hier.u.var.name = pnt = xc->str_scope_nam;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
*(pnt++) = ch;
|
||||
if(cl <= FST_ID_NAM_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* varname */
|
||||
*pnt = 0;
|
||||
xc->hier.u.var.name_length = pnt - xc->hier.u.var.name;
|
||||
pnt[cl] = 0;
|
||||
xc->hier.u.var.name_length = cl;
|
||||
xc->hier.u.var.length = fstReaderVarint32(xc->fh);
|
||||
if(tag == FST_VT_VCD_PORT)
|
||||
{
|
||||
@@ -4273,6 +4290,7 @@ unsigned int num_signal_dyn = 65536;
|
||||
int attrtype, subtype;
|
||||
uint64_t attrarg;
|
||||
fstHandle maxhandle_scanbuild;
|
||||
int cl;
|
||||
|
||||
if(!xc) return(0);
|
||||
|
||||
@@ -4355,11 +4373,15 @@ while(!feof(xc->fh))
|
||||
scopetype = fgetc(xc->fh);
|
||||
if((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) scopetype = FST_ST_VCD_MODULE;
|
||||
pnt = str;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
*(pnt++) = ch;
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* scopename */
|
||||
*pnt = 0;
|
||||
pnt[cl] = 0;
|
||||
while(fgetc(xc->fh)) { }; /* scopecomp */
|
||||
|
||||
if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str);
|
||||
@@ -4373,11 +4395,15 @@ while(!feof(xc->fh))
|
||||
attrtype = fgetc(xc->fh);
|
||||
subtype = fgetc(xc->fh);
|
||||
pnt = str;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
*(pnt++) = ch;
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* attrname */
|
||||
*pnt = 0;
|
||||
pnt[cl] = 0;
|
||||
|
||||
if(!str[0]) { strcpy(str, "\"\""); }
|
||||
|
||||
@@ -4458,11 +4484,15 @@ while(!feof(xc->fh))
|
||||
vartype = tag;
|
||||
/* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */
|
||||
pnt = str;
|
||||
cl = 0;
|
||||
while((ch = fgetc(xc->fh)))
|
||||
{
|
||||
*(pnt++) = ch;
|
||||
if(cl <= FST_ID_NAM_ATTR_SIZ)
|
||||
{
|
||||
pnt[cl++] = ch;
|
||||
}
|
||||
}; /* varname */
|
||||
*pnt = 0;
|
||||
pnt[cl] = 0;
|
||||
len = fstReaderVarint32(xc->fh);
|
||||
alias = fstReaderVarint32(xc->fh);
|
||||
|
||||
|
||||
+306
-215
File diff suppressed because it is too large
Load Diff
+123
-72
@@ -54,11 +54,9 @@
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
// <iostream> avoided to reduce compile time
|
||||
#ifdef VL_THREADED
|
||||
# include <atomic>
|
||||
# include <mutex>
|
||||
# include <thread>
|
||||
#endif
|
||||
#include <atomic>
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
// Allow user to specify their own include file
|
||||
#ifdef VL_VERILATED_INCLUDE
|
||||
@@ -81,6 +79,7 @@
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
class VerilatedContext;
|
||||
class VerilatedContextImp;
|
||||
class VerilatedContextImpData;
|
||||
class VerilatedCovContext;
|
||||
@@ -90,6 +89,9 @@ class VerilatedFstC;
|
||||
class VerilatedFstSc;
|
||||
class VerilatedScope;
|
||||
class VerilatedScopeNameMap;
|
||||
template <class, class>
|
||||
class VerilatedTrace;
|
||||
class VerilatedTraceConfig;
|
||||
class VerilatedVar;
|
||||
class VerilatedVarNameMap;
|
||||
class VerilatedVcd;
|
||||
@@ -145,8 +147,6 @@ enum VerilatedVarFlags {
|
||||
// Return current thread ID (or 0), not super fast, cache if needed
|
||||
extern uint32_t VL_THREAD_ID() VL_MT_SAFE;
|
||||
|
||||
#if VL_THREADED
|
||||
|
||||
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding
|
||||
|
||||
/// Mutex, wrapped to allow -fthread_safety checks
|
||||
@@ -160,7 +160,7 @@ public:
|
||||
~VerilatedMutex() = default;
|
||||
const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety
|
||||
/// Acquire/lock mutex
|
||||
void lock() VL_ACQUIRE() {
|
||||
void lock() VL_ACQUIRE() VL_MT_SAFE {
|
||||
// Try to acquire the lock by spinning. If the wait is short,
|
||||
// avoids a trap to the OS plus OS scheduler overhead.
|
||||
if (VL_LIKELY(try_lock())) return; // Short circuit loop
|
||||
@@ -172,9 +172,9 @@ public:
|
||||
m_mutex.lock();
|
||||
}
|
||||
/// Release/unlock mutex
|
||||
void unlock() VL_RELEASE() { 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.
|
||||
bool try_lock() VL_TRY_ACQUIRE(true) { return m_mutex.try_lock(); }
|
||||
bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return m_mutex.try_lock(); }
|
||||
};
|
||||
|
||||
/// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks
|
||||
@@ -186,46 +186,24 @@ private:
|
||||
|
||||
public:
|
||||
/// Construct and hold given mutex lock until destruction or unlock()
|
||||
explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr)
|
||||
explicit VerilatedLockGuard(VerilatedMutex& mutexr) VL_ACQUIRE(mutexr) VL_MT_SAFE
|
||||
: m_mutexr(mutexr) { // Need () or GCC 4.8 false warning
|
||||
m_mutexr.lock();
|
||||
}
|
||||
/// Destruct and unlock the mutex
|
||||
~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); }
|
||||
/// Unlock the mutex
|
||||
void lock() VL_ACQUIRE() { m_mutexr.lock(); }
|
||||
void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); }
|
||||
/// Lock the mutex
|
||||
void unlock() VL_RELEASE() { m_mutexr.unlock(); }
|
||||
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); }
|
||||
};
|
||||
|
||||
#else // !VL_THREADED
|
||||
|
||||
// Empty non-threaded mutex to avoid #ifdefs in consuming code
|
||||
class VerilatedMutex final {
|
||||
public:
|
||||
void lock() {} // LCOV_EXCL_LINE
|
||||
void unlock() {} // LCOV_EXCL_LINE
|
||||
};
|
||||
|
||||
// Empty non-threaded lock guard to avoid #ifdefs in consuming code
|
||||
class VerilatedLockGuard final {
|
||||
VL_UNCOPYABLE(VerilatedLockGuard);
|
||||
|
||||
public:
|
||||
explicit VerilatedLockGuard(VerilatedMutex&) {}
|
||||
~VerilatedLockGuard() = default;
|
||||
void lock() {} // LCOV_EXCL_LINE
|
||||
void unlock() {} // LCOV_EXCL_LINE
|
||||
};
|
||||
|
||||
#endif // VL_THREADED
|
||||
|
||||
// Internals: Remember the calling thread at construction time, and make
|
||||
// sure later calls use same thread
|
||||
|
||||
class VerilatedAssertOneThread final {
|
||||
// MEMBERS
|
||||
#if defined(VL_THREADED) && defined(VL_DEBUG)
|
||||
#ifdef VL_DEBUG
|
||||
uint32_t m_threadid; // Thread that is legal
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
@@ -246,12 +224,46 @@ public:
|
||||
}
|
||||
}
|
||||
static void fatal_different() VL_MT_SAFE;
|
||||
#else // !VL_THREADED || !VL_DEBUG
|
||||
#else // !VL_DEBUG
|
||||
public:
|
||||
void check() {}
|
||||
#endif
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
/// Base class of a Verilator generated (Verilated) model.
|
||||
///
|
||||
/// VerilatedModel is a base class of the user facing primary class generated
|
||||
/// by Verilator.
|
||||
|
||||
class VerilatedModel VL_NOT_FINAL {
|
||||
VL_UNCOPYABLE(VerilatedModel);
|
||||
|
||||
VerilatedContext& m_context; // The VerilatedContext this model is instantiated under
|
||||
|
||||
protected:
|
||||
explicit VerilatedModel(VerilatedContext& context);
|
||||
virtual ~VerilatedModel() = default;
|
||||
|
||||
public:
|
||||
/// Returns the VerilatedContext this model is instantiated under
|
||||
/// Used to get to e.g. simulation time via contextp()->time()
|
||||
VerilatedContext* contextp() const VL_MT_SAFE { return &m_context; }
|
||||
/// Returns the hierarchical name of this module instance.
|
||||
virtual const char* hierName() const = 0;
|
||||
/// Returns the name of this model (the name of the generated model class).
|
||||
virtual const char* modelName() const = 0;
|
||||
/// Returns the thread level parallelism, this model was Verilated with. Always 1 or higher.
|
||||
virtual unsigned threads() const = 0;
|
||||
|
||||
private:
|
||||
// The following are for use by Verilator internals only
|
||||
template <class, class>
|
||||
friend class VerilatedTrace;
|
||||
// Run-time trace configuration requested by this model
|
||||
virtual std::unique_ptr<VerilatedTraceConfig> traceConfig() const;
|
||||
};
|
||||
|
||||
//=========================================================================
|
||||
/// Base class for all Verilated module classes.
|
||||
|
||||
@@ -263,13 +275,9 @@ private:
|
||||
public:
|
||||
explicit VerilatedModule(const char* namep); // Create module with given hierarchy name
|
||||
~VerilatedModule();
|
||||
const char* name() const { return m_namep; } ///< Return name of module
|
||||
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; } ///< Return name of module
|
||||
};
|
||||
|
||||
/// Declare a module, ala SC_MODULE
|
||||
#define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule
|
||||
// Not class final in VL_MODULE, as users might be abstracting our models (--hierarchical)
|
||||
|
||||
//=========================================================================
|
||||
// Functions overridable by user defines
|
||||
// (Internals however must use VL_PRINTF_MT, which calls these.)
|
||||
@@ -309,7 +317,7 @@ class VerilatedContext VL_NOT_FINAL {
|
||||
protected:
|
||||
// MEMBERS
|
||||
// Slow path variables
|
||||
mutable VerilatedMutex m_mutex; // Mutex for most s_s/s_ns members, when VL_THREADED
|
||||
mutable VerilatedMutex m_mutex; // Mutex for most s_s/s_ns members
|
||||
|
||||
struct Serialized { // All these members serialized/deserialized
|
||||
// No std::strings or pointers or will serialize badly!
|
||||
@@ -356,12 +364,18 @@ protected:
|
||||
// assumption is that the restore is allowed to pass different arguments
|
||||
struct NonSerializedCommandArgs {
|
||||
// Medium speed
|
||||
bool m_argVecLoaded = false; // Ever loaded argument list
|
||||
std::vector<std::string> m_argVec; // Aargument list
|
||||
bool m_argVecLoaded = false; // Ever loaded argument list
|
||||
} m_args VL_GUARDED_BY(m_argMutex);
|
||||
|
||||
// Implementation details
|
||||
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
|
||||
// Number of threads to use for simulation (size of m_threadPool + 1 for main thread)
|
||||
unsigned m_threads = std::thread::hardware_concurrency();
|
||||
// The thread pool shared by all models added to this context
|
||||
std::unique_ptr<VerilatedVirtualBase> m_threadPool;
|
||||
// The execution profiler shared by all models added to this context
|
||||
std::unique_ptr<VerilatedVirtualBase> m_executionProfiler;
|
||||
// Coverage access
|
||||
std::unique_ptr<VerilatedVirtualBase> m_coveragep; // Pointer for coveragep()
|
||||
|
||||
@@ -413,9 +427,9 @@ public:
|
||||
VerilatedCovContext* coveragep() VL_MT_SAFE;
|
||||
/// Set debug level
|
||||
/// Debug is currently global, but for forward compatibility have a per-context method
|
||||
static void debug(int val) VL_MT_SAFE;
|
||||
static inline void debug(int val) VL_MT_SAFE;
|
||||
/// Return debug level
|
||||
static int debug() VL_MT_SAFE;
|
||||
static inline int debug() VL_MT_SAFE;
|
||||
/// Set current number of errors/assertions
|
||||
void errorCount(int val) VL_MT_SAFE;
|
||||
/// Increment current number of errors/assertions
|
||||
@@ -426,7 +440,7 @@ public:
|
||||
void errorLimit(int val) VL_MT_SAFE;
|
||||
/// Return number of errors/assertions before stop
|
||||
int errorLimit() const VL_MT_SAFE { return m_s.m_errorLimit; }
|
||||
/// Set to throw fatal error on $stop/non-fatal ettot
|
||||
/// Set to throw fatal error on $stop/non-fatal error
|
||||
void fatalOnError(bool flag) VL_MT_SAFE;
|
||||
/// Return if to throw fatal error on $stop/non-fatal
|
||||
bool fatalOnError() const VL_MT_SAFE { return m_s.m_fatalOnError; }
|
||||
@@ -477,7 +491,7 @@ public:
|
||||
///
|
||||
/// * Else, time comes from the legacy 'double sc_time_stamp()' which
|
||||
/// must be a function defined by the user's wrapper.
|
||||
uint64_t time() const VL_MT_SAFE;
|
||||
inline uint64_t time() const VL_MT_SAFE;
|
||||
/// Set current simulation time. See time() for side effect details
|
||||
void time(uint64_t value) VL_MT_SAFE { m_s.m_time = value; }
|
||||
/// Advance current simulation time. See time() for side effect details
|
||||
@@ -491,10 +505,16 @@ public:
|
||||
/// Get time precision as power-of-ten
|
||||
int timeprecision() const VL_MT_SAFE { return -m_s.m_timeprecision; }
|
||||
/// Return time precision as power-of-ten
|
||||
void timeprecision(int value) VL_MT_SAFE;
|
||||
inline void timeprecision(int value) VL_MT_SAFE;
|
||||
/// Get time precision as IEEE-standard text
|
||||
const char* timeprecisionString() const VL_MT_SAFE;
|
||||
|
||||
/// Get number of threads used for simulation (including the main thread)
|
||||
unsigned threads() const { return m_threads; }
|
||||
/// Set number of threads used for simulation (including the main thread)
|
||||
/// Can only be called before the thread pool is created (before first model is added).
|
||||
void threads(unsigned n);
|
||||
|
||||
/// Allow traces to at some point be enabled (disables some optimizations)
|
||||
void traceEverOn(bool flag) VL_MT_SAFE {
|
||||
if (flag) calcUnusedSigs(true);
|
||||
@@ -510,13 +530,20 @@ public:
|
||||
/// releases - contact the authors before production use.
|
||||
void scopesDump() const VL_MT_SAFE;
|
||||
|
||||
public: // But for internal use only
|
||||
// METHODS - public but for internal use only
|
||||
|
||||
// Internal: access to implementation class
|
||||
VerilatedContextImp* impp() { return reinterpret_cast<VerilatedContextImp*>(this); }
|
||||
const VerilatedContextImp* impp() const {
|
||||
VerilatedContextImp* impp() VL_MT_SAFE { return reinterpret_cast<VerilatedContextImp*>(this); }
|
||||
const VerilatedContextImp* impp() const VL_MT_SAFE {
|
||||
return reinterpret_cast<const VerilatedContextImp*>(this);
|
||||
}
|
||||
|
||||
void addModel(VerilatedModel*);
|
||||
|
||||
VerilatedVirtualBase* threadPoolp();
|
||||
VerilatedVirtualBase*
|
||||
enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&));
|
||||
|
||||
// Internal: $dumpfile
|
||||
void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
std::string dumpfile() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex);
|
||||
@@ -554,9 +581,7 @@ public: // But for internal use only
|
||||
// MEMBERS
|
||||
// Keep first so is at zero offset for fastest code
|
||||
VerilatedContext* const _vm_contextp__; // Context for current model
|
||||
#ifdef VL_THREADED
|
||||
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
|
||||
#endif
|
||||
explicit VerilatedSyms(VerilatedContext* contextp); // Pass null for default context
|
||||
~VerilatedSyms();
|
||||
};
|
||||
@@ -592,16 +617,16 @@ public: // But internals only - called from VerilatedModule's
|
||||
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
||||
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
|
||||
// ACCESSORS
|
||||
const char* name() const { return m_namep; }
|
||||
const char* identifier() const { return m_identifierp; }
|
||||
int8_t timeunit() const { return m_timeunit; }
|
||||
inline VerilatedSyms* symsp() const { return m_symsp; }
|
||||
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; }
|
||||
const char* identifier() const VL_MT_SAFE_POSTINIT { return m_identifierp; }
|
||||
int8_t timeunit() const VL_MT_SAFE_POSTINIT { return m_timeunit; }
|
||||
VerilatedSyms* symsp() const VL_MT_SAFE_POSTINIT { return m_symsp; }
|
||||
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
|
||||
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
|
||||
void scopeDump() const;
|
||||
void* exportFindError(int funcnum) const;
|
||||
static void* exportFindNullError(int funcnum) VL_MT_SAFE;
|
||||
static inline void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
|
||||
static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum);
|
||||
if (VL_LIKELY(funcnum < scopep->m_funcnumMax)) {
|
||||
// m_callbacksp must be declared, as Max'es are > 0
|
||||
@@ -637,17 +662,15 @@ class Verilated final {
|
||||
static VerilatedContext* s_lastContextp; // Last context constructed/attached
|
||||
|
||||
// Not covered by mutex, as per-thread
|
||||
static VL_THREAD_LOCAL struct ThreadLocal {
|
||||
static thread_local struct ThreadLocal {
|
||||
// No non-POD objects here due to this:
|
||||
// Internal note: Globals may multi-construct, see verilated.cpp top.
|
||||
|
||||
// Fast path
|
||||
VerilatedContext* t_contextp = nullptr; // Thread's context
|
||||
#ifdef VL_THREADED
|
||||
uint32_t t_mtaskId = 0; // mtask# executing on this thread
|
||||
// Messages maybe pending on thread, needs end-of-eval calls
|
||||
uint32_t t_endOfEvalReqd = 0;
|
||||
#endif
|
||||
const VerilatedScope* t_dpiScopep = nullptr; // DPI context scope
|
||||
const char* t_dpiFilename = nullptr; // DPI context filename
|
||||
int t_dpiLineno = 0; // DPI context line number
|
||||
@@ -670,7 +693,7 @@ public:
|
||||
/// Return debug level
|
||||
/// When multithreaded this may not immediately react to another thread
|
||||
/// changing the level (no mutex)
|
||||
static inline int debug() VL_MT_SAFE { return s_debug; }
|
||||
static int debug() VL_MT_SAFE { return s_debug; }
|
||||
#else
|
||||
/// Return constant 0 debug level, so C++'s optimizer rips up
|
||||
static constexpr int debug() VL_PURE { return 0; }
|
||||
@@ -695,7 +718,7 @@ public:
|
||||
lastContextp(contextp);
|
||||
}
|
||||
/// Return the VerilatedContext for the current thread
|
||||
static VerilatedContext* threadContextp() {
|
||||
static VerilatedContext* threadContextp() VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!t_s.t_contextp)) t_s.t_contextp = lastContextp();
|
||||
return t_s.t_contextp;
|
||||
}
|
||||
@@ -830,15 +853,17 @@ public:
|
||||
}
|
||||
#endif
|
||||
|
||||
public:
|
||||
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
|
||||
// Internal: Create a new module name by concatenating two strings
|
||||
// Returns pointer to thread-local static data (overwritten on next call)
|
||||
static const char* catName(const char* n1, const char* n2, const char* delimiter = ".");
|
||||
static const char* catName(const char* n1, const char* n2,
|
||||
const char* delimiter = ".") VL_MT_SAFE;
|
||||
|
||||
// Internal: Throw signal assertion
|
||||
static void nullPointerError(const char* filename, int linenum) VL_ATTR_NORETURN VL_MT_SAFE;
|
||||
static void overWidthError(const char* signame) VL_ATTR_NORETURN VL_MT_SAFE;
|
||||
static void scTimePrecisionError(int sc_prec, int vl_prec) VL_ATTR_NORETURN VL_MT_SAFE;
|
||||
static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE;
|
||||
|
||||
// Internal: Get and set DPI context
|
||||
static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; }
|
||||
@@ -855,7 +880,6 @@ public:
|
||||
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
|
||||
static int exportFuncNum(const char* namep) VL_MT_SAFE;
|
||||
|
||||
#ifdef VL_THREADED
|
||||
// Internal: Set the mtaskId, called when an mtask starts
|
||||
// Per thread, so no need to be in VerilatedContext
|
||||
static void mtaskId(uint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; }
|
||||
@@ -869,16 +893,13 @@ public:
|
||||
}
|
||||
// Internal: Called at end of eval loop
|
||||
static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
|
||||
#endif
|
||||
|
||||
private:
|
||||
#ifdef VL_THREADED
|
||||
static void endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
|
||||
#endif
|
||||
};
|
||||
|
||||
inline void VerilatedContext::debug(int val) VL_MT_SAFE { Verilated::debug(val); }
|
||||
inline int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); }
|
||||
void VerilatedContext::debug(int val) VL_MT_SAFE { Verilated::debug(val); }
|
||||
int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); }
|
||||
|
||||
//=========================================================================
|
||||
// Data Types
|
||||
@@ -892,5 +913,35 @@ inline int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); }
|
||||
|
||||
//======================================================================
|
||||
|
||||
void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
|
||||
if (value < 0) value = -value; // Stored as 0..15
|
||||
#if VM_SC
|
||||
int sc_prec = 99;
|
||||
#endif
|
||||
{
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
m_s.m_timeprecision = value;
|
||||
#if VM_SC
|
||||
const sc_time sc_res = sc_get_time_resolution();
|
||||
if (sc_res == sc_time(1, SC_SEC)) {
|
||||
sc_prec = 0;
|
||||
} else if (sc_res == sc_time(1, SC_MS)) {
|
||||
sc_prec = 3;
|
||||
} else if (sc_res == sc_time(1, SC_US)) {
|
||||
sc_prec = 6;
|
||||
} else if (sc_res == sc_time(1, SC_NS)) {
|
||||
sc_prec = 9;
|
||||
} else if (sc_res == sc_time(1, SC_PS)) {
|
||||
sc_prec = 12;
|
||||
} else if (sc_res == sc_time(1, SC_FS)) {
|
||||
sc_prec = 15;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#if VM_SC
|
||||
if (VL_UNLIKELY(value != sc_prec)) Verilated::scTimePrecisionError(sc_prec, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef VERILATOR_VERILATED_H_INTERNAL_
|
||||
#endif // Guard
|
||||
|
||||
+9
-44
@@ -27,6 +27,8 @@ CFG_CXXFLAGS_STD_NEWEST = @CFG_CXXFLAGS_STD_NEWEST@
|
||||
CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
|
||||
# Compiler flags that turn on extra warnings
|
||||
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
|
||||
# Compiler flags that enable coroutine support
|
||||
CFG_CXXFLAGS_COROUTINES = @CFG_CXXFLAGS_COROUTINES@
|
||||
# Linker libraries for multithreading
|
||||
CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@
|
||||
|
||||
@@ -128,52 +130,15 @@ endif
|
||||
#######################################################################
|
||||
##### Threaded builds
|
||||
|
||||
ifneq ($(VM_C11),0)
|
||||
ifneq ($(VM_C11),)
|
||||
VK_C11=1
|
||||
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
|
||||
LDLIBS += $(CFG_LDLIBS_THREADS)
|
||||
|
||||
ifneq ($(VM_TIMING),0)
|
||||
ifneq ($(VM_TIMING),)
|
||||
CPPFLAGS += $(CFG_CXXFLAGS_COROUTINES)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(VM_THREADS),0)
|
||||
ifneq ($(VM_THREADS),)
|
||||
CPPFLAGS += -DVL_THREADED
|
||||
VK_C11=1
|
||||
VK_LIBS_THREADED=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(VM_TRACE_THREADS),0)
|
||||
ifneq ($(VM_TRACE_THREADS),)
|
||||
ifeq ($(findstring -DVL_THREADED,$(CPPFLAGS)),)
|
||||
$(error VM_TRACE_THREADS requires VM_THREADS)
|
||||
endif
|
||||
CPPFLAGS += -DVL_TRACE_THREADED
|
||||
VK_C11=1
|
||||
VK_LIBS_THREADED=1
|
||||
endif
|
||||
endif
|
||||
|
||||
|
||||
ifneq ($(VM_TRACE_FST_WRITER_THREAD),0)
|
||||
ifneq ($(VM_TRACE_FST_WRITER_THREAD),)
|
||||
CPPFLAGS += -DVL_TRACE_FST_WRITER_THREAD
|
||||
VK_C11=1
|
||||
VK_LIBS_THREADED=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(VK_C11),0)
|
||||
ifneq ($(VK_C11),)
|
||||
# Need C++11 at least, so always default to newest
|
||||
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(VK_LIBS_THREADED),0)
|
||||
ifneq ($(VK_LIBS_THREADED),)
|
||||
LDLIBS += $(CFG_LDLIBS_THREADS)
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
### Aggregates
|
||||
@@ -187,7 +152,7 @@ VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
|
||||
VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
|
||||
VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
|
||||
|
||||
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
|
||||
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
|
||||
|
||||
# Note VM_GLOBAL_FAST and VM_GLOBAL_SLOW holds the files required from the
|
||||
# run-time library. In practice everything is actually in VM_GLOBAL_FAST,
|
||||
|
||||
+13
-11
@@ -22,8 +22,10 @@
|
||||
//=============================================================================
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#include "verilated_cov.h"
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_cov_key.h"
|
||||
|
||||
#include <deque>
|
||||
@@ -69,22 +71,23 @@ public: // But only local to this file
|
||||
// This isn't in the header file for auto-magic conversion because it
|
||||
// inlines to too much code and makes compilation too slow.
|
||||
|
||||
template <class T> class VerilatedCoverItemSpec final : public VerilatedCovImpItem {
|
||||
template <class T>
|
||||
class VerilatedCoverItemSpec final : public VerilatedCovImpItem {
|
||||
private:
|
||||
// MEMBERS
|
||||
T* m_countp; // Count value
|
||||
public:
|
||||
// METHODS
|
||||
// cppcheck-suppress truncLongCastReturn
|
||||
virtual uint64_t count() const override { return *m_countp; }
|
||||
virtual void zero() const override { *m_countp = 0; }
|
||||
uint64_t count() const override { return *m_countp; }
|
||||
void zero() const override { *m_countp = 0; }
|
||||
// CONSTRUCTORS
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
explicit VerilatedCoverItemSpec(T* countp)
|
||||
: m_countp{countp} {
|
||||
*m_countp = 0;
|
||||
}
|
||||
virtual ~VerilatedCoverItemSpec() override = default;
|
||||
~VerilatedCoverItemSpec() override = default;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -122,7 +125,7 @@ public:
|
||||
|
||||
protected:
|
||||
friend class VerilatedCovContext;
|
||||
virtual ~VerilatedCovImp() override { clearGuts(); }
|
||||
~VerilatedCovImp() override { clearGuts(); }
|
||||
|
||||
private:
|
||||
// PRIVATE METHODS
|
||||
@@ -205,7 +208,7 @@ private:
|
||||
// Forward to . so we have a whole word
|
||||
const std::string suffix = *bpost ? std::string{bpost + 1} : "";
|
||||
|
||||
const std::string out = prefix + "*" + suffix;
|
||||
std::string out = prefix + "*" + suffix;
|
||||
|
||||
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
|
||||
// <<"\ncho="<<out<<endl;
|
||||
@@ -354,9 +357,6 @@ public:
|
||||
void write(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
#ifndef VM_COVERAGE
|
||||
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled");
|
||||
#endif
|
||||
selftest();
|
||||
|
||||
std::ofstream os{filename};
|
||||
@@ -511,9 +511,11 @@ VerilatedCovContext* VerilatedCov::threadCovp() VL_MT_SAFE {
|
||||
|
||||
VerilatedCovContext* VerilatedContext::coveragep() VL_MT_SAFE {
|
||||
static VerilatedMutex s_mutex;
|
||||
// cppcheck-suppress identicalInnerCondition
|
||||
if (VL_UNLIKELY(!m_coveragep)) {
|
||||
const VerilatedLockGuard lock{s_mutex};
|
||||
if (VL_LIKELY(!m_coveragep)) { // Not redundant, prevents race
|
||||
// cppcheck-suppress identicalInnerCondition
|
||||
if (VL_LIKELY(!m_coveragep)) { // LCOV_EXCL_LINE // Not redundant, prevents race
|
||||
m_coveragep.reset(new VerilatedCovImp);
|
||||
}
|
||||
}
|
||||
|
||||
+17
-27
@@ -26,6 +26,7 @@
|
||||
#define VERILATOR_VERILATED_COV_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <iostream>
|
||||
@@ -35,23 +36,7 @@
|
||||
class VerilatedCovImp;
|
||||
|
||||
//=============================================================================
|
||||
/// Conditionally compile statements only when doing coverage (when
|
||||
/// VM_COVERAGE is defined)
|
||||
|
||||
// clang-format off
|
||||
#ifdef VM_COVERAGE
|
||||
# define VL_IF_COVER(stmts) \
|
||||
do { stmts; } while (false)
|
||||
#else
|
||||
# define VL_IF_COVER(stmts) \
|
||||
do { \
|
||||
if (false) { stmts; } \
|
||||
} while (false)
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
//=============================================================================
|
||||
/// Insert a item for coverage analysis.
|
||||
/// Insert an item for coverage analysis.
|
||||
/// The first argument is a pointer to the count to be dumped.
|
||||
/// The remaining arguments occur in pairs: A string key, and a value.
|
||||
/// The value may be a string, or another type which will be auto-converted to a string.
|
||||
@@ -82,13 +67,17 @@ class VerilatedCovImp;
|
||||
/// }
|
||||
|
||||
#define VL_COVER_INSERT(covcontextp, countp, ...) \
|
||||
VL_IF_COVER(covcontextp->_inserti(countp); covcontextp->_insertf(__FILE__, __LINE__); \
|
||||
covcontextp->_insertp("hier", name(), __VA_ARGS__))
|
||||
do { \
|
||||
covcontextp->_inserti(countp); \
|
||||
covcontextp->_insertf(__FILE__, __LINE__); \
|
||||
covcontextp->_insertp("hier", name(), __VA_ARGS__); \
|
||||
} while (false)
|
||||
|
||||
//=============================================================================
|
||||
// Convert VL_COVER_INSERT value arguments to strings, is \internal
|
||||
|
||||
template <class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
|
||||
template <class T>
|
||||
std::string vlCovCvtToStr(const T& t) VL_PURE {
|
||||
std::ostringstream os;
|
||||
os << t;
|
||||
return os.str();
|
||||
@@ -120,7 +109,8 @@ public:
|
||||
/// Zero coverage points
|
||||
void zero() VL_MT_SAFE;
|
||||
|
||||
public: // But Internal use only
|
||||
// METHODS - public but Internal use only
|
||||
|
||||
// Insert a coverage item
|
||||
// We accept from 1-30 key/value pairs, all as strings.
|
||||
// Call _insert1, followed by _insert2 and _insert3
|
||||
@@ -138,15 +128,15 @@ public: // But Internal use only
|
||||
#define K(n) const char* key##n
|
||||
#define A(n) const char *key##n, const char *valp##n // Argument list
|
||||
#define D(n) const char *key##n = nullptr, const char *valp##n = nullptr // Argument list
|
||||
void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9));
|
||||
void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9)) VL_MT_SAFE;
|
||||
void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), D(11), D(12),
|
||||
D(13), D(14), D(15), D(16), D(17), D(18), D(19));
|
||||
D(13), D(14), D(15), D(16), D(17), D(18), D(19)) VL_MT_SAFE;
|
||||
void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), A(11), A(12),
|
||||
A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20), D(21), D(22), D(23),
|
||||
D(24), D(25), D(26), D(27), D(28), D(29));
|
||||
D(24), D(25), D(26), D(27), D(28), D(29)) VL_MT_SAFE;
|
||||
// Backward compatibility for Verilator
|
||||
void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4, A(5),
|
||||
A(6), A(7));
|
||||
A(6), A(7)) VL_MT_SAFE;
|
||||
|
||||
#undef K
|
||||
#undef A
|
||||
@@ -158,11 +148,11 @@ protected:
|
||||
// CONSTRUCTORS
|
||||
// Internal: Only made as part of VerilatedCovImp
|
||||
VerilatedCovContext() = default;
|
||||
virtual ~VerilatedCovContext() = default;
|
||||
~VerilatedCovContext() override = default;
|
||||
|
||||
// METHODS
|
||||
// Internal: access to implementation class
|
||||
VerilatedCovImp* impp() { return reinterpret_cast<VerilatedCovImp*>(this); }
|
||||
VerilatedCovImp* impp() VL_MT_SAFE { return reinterpret_cast<VerilatedCovImp*>(this); }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
@@ -28,7 +28,9 @@
|
||||
#define VERILATOR_VERILATED_DPI_CPP_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated_dpi.h"
|
||||
|
||||
#include "verilated_imp.h"
|
||||
|
||||
// On MSVC++ we need svdpi.h to declare exports, not imports
|
||||
@@ -179,7 +181,7 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w
|
||||
//======================================================================
|
||||
// Open array internals
|
||||
|
||||
static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) {
|
||||
static const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!h)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"%%Error: DPI svOpenArrayHandle function called with nullptr handle");
|
||||
@@ -221,7 +223,7 @@ int svSizeOfArray(const svOpenArrayHandle h) {
|
||||
// Open array access internals
|
||||
|
||||
static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, int indx1,
|
||||
int indx2, int indx3) {
|
||||
int indx2, int indx3) VL_MT_SAFE {
|
||||
void* datap = varp->datap();
|
||||
if (VL_UNLIKELY(nargs != varp->udims())) {
|
||||
VL_SVDPI_WARN_("%%Warning: DPI svOpenArrayHandle function called on"
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#define VERILATOR_VERILATED_DPI_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated.h" // Also presumably included by caller
|
||||
#include "verilated_sym_props.h"
|
||||
|
||||
|
||||
+37
-23
@@ -28,10 +28,8 @@
|
||||
#include "verilated_fst_c.h"
|
||||
|
||||
// GTKWave configuration
|
||||
#ifdef VL_TRACE_FST_WRITER_THREAD
|
||||
# define HAVE_LIBPTHREAD
|
||||
# define FST_WRITER_PARALLEL
|
||||
#endif
|
||||
#define HAVE_LIBPTHREAD
|
||||
#define FST_WRITER_PARALLEL
|
||||
|
||||
// Include the GTKWave implementation directly
|
||||
#define FST_CONFIG_INCLUDE "fst_config.h"
|
||||
@@ -92,13 +90,12 @@ static_assert(static_cast<int>(FST_ST_VCD_PROGRAM) == static_cast<int>(VLT_TRACE
|
||||
//=============================================================================
|
||||
// VerilatedFst
|
||||
|
||||
VerilatedFst::VerilatedFst(void* fst)
|
||||
: m_fst{fst} {}
|
||||
VerilatedFst::VerilatedFst(void* /*fst*/) {}
|
||||
|
||||
VerilatedFst::~VerilatedFst() {
|
||||
if (m_fst) fstWriterClose(m_fst);
|
||||
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = nullptr);
|
||||
if (m_strbuf) VL_DO_CLEAR(delete[] m_strbuf, m_strbuf = nullptr);
|
||||
if (m_strbufp) VL_DO_CLEAR(delete[] m_strbufp, m_strbufp = nullptr);
|
||||
}
|
||||
|
||||
void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
@@ -106,9 +103,7 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
m_fst = fstWriterCreate(filename, 1);
|
||||
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
|
||||
fstWriterSetTimescaleFromString(m_fst, timeResStr().c_str()); // lintok-begin-on-ref
|
||||
#ifdef VL_TRACE_FST_WRITER_THREAD
|
||||
fstWriterSetParallelMode(m_fst, 1);
|
||||
#endif
|
||||
if (m_useFstWriterThread) fstWriterSetParallelMode(m_fst, 1);
|
||||
fullDump(true); // First dump must be full for fst
|
||||
|
||||
m_curScope.clear();
|
||||
@@ -130,7 +125,7 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
m_code2symbol.clear();
|
||||
|
||||
// Allocate string buffer for arrays
|
||||
if (!m_strbuf) m_strbuf = new char[maxBits() + 32];
|
||||
if (!m_strbufp) m_strbufp = new char[maxBits() + 32];
|
||||
}
|
||||
|
||||
void VerilatedFst::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
@@ -226,6 +221,10 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, fstVar
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedFst::declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
|
||||
}
|
||||
void VerilatedFst::declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
|
||||
@@ -250,23 +249,32 @@ void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum, fst
|
||||
//=============================================================================
|
||||
// Get/commit trace buffer
|
||||
|
||||
VerilatedFstBuffer* VerilatedFst::getTraceBuffer() { return new VerilatedFstBuffer{*this}; }
|
||||
VerilatedFst::Buffer* VerilatedFst::getTraceBuffer() {
|
||||
if (offload()) return new OffloadBuffer{*this};
|
||||
return new Buffer{*this};
|
||||
}
|
||||
|
||||
void VerilatedFst::commitTraceBuffer(VerilatedFstBuffer* bufp) {
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
if (bufp->m_offloadBufferWritep) {
|
||||
m_offloadBufferWritep = bufp->m_offloadBufferWritep;
|
||||
return; // Buffer will be deleted by the offload thread
|
||||
void VerilatedFst::commitTraceBuffer(VerilatedFst::Buffer* bufp) {
|
||||
if (offload()) {
|
||||
OffloadBuffer* const offloadBufferp = static_cast<OffloadBuffer*>(bufp);
|
||||
if (offloadBufferp->m_offloadBufferWritep) {
|
||||
m_offloadBufferWritep = offloadBufferp->m_offloadBufferWritep;
|
||||
return; // Buffer will be deleted by the offload thread
|
||||
}
|
||||
}
|
||||
#endif
|
||||
delete bufp;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedFstBuffer implementation
|
||||
// Configure
|
||||
|
||||
VerilatedFstBuffer::VerilatedFstBuffer(VerilatedFst& owner)
|
||||
: VerilatedTraceBuffer<VerilatedFst, VerilatedFstBuffer>{owner} {}
|
||||
void VerilatedFst::configure(const VerilatedTraceConfig& config) {
|
||||
// If at least one model requests the FST writer thread, then use it
|
||||
m_useFstWriterThread |= config.m_useFstWriterThread;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedFstBuffer implementation
|
||||
|
||||
//=============================================================================
|
||||
// Trace rendering primitives
|
||||
@@ -275,6 +283,12 @@ VerilatedFstBuffer::VerilatedFstBuffer(VerilatedFst& owner)
|
||||
// verilated_trace_imp.h, which is included in this file at the top),
|
||||
// so always inline them.
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitEvent(uint32_t code, VlEvent newval) {
|
||||
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) {
|
||||
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
|
||||
@@ -316,7 +330,7 @@ void VerilatedFstBuffer::emitQData(uint32_t code, QData newval, int bits) {
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFstBuffer::emitWData(uint32_t code, const WData* newvalp, int bits) {
|
||||
int words = VL_WORDS_I(bits);
|
||||
char* wp = m_strbuf;
|
||||
char* wp = m_strbufp;
|
||||
// Convert the most significant word
|
||||
const int bitsInMSW = VL_BITBIT_E(bits) ? VL_BITBIT_E(bits) : VL_EDATASIZE;
|
||||
cvtEDataToStr(wp, newvalp[--words] << (VL_EDATASIZE - bitsInMSW));
|
||||
@@ -326,7 +340,7 @@ void VerilatedFstBuffer::emitWData(uint32_t code, const WData* newvalp, int bits
|
||||
cvtEDataToStr(wp, newvalp[--words]);
|
||||
wp += VL_EDATASIZE;
|
||||
}
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf);
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbufp);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
|
||||
+45
-27
@@ -43,17 +43,19 @@ public:
|
||||
using Super = VerilatedTrace<VerilatedFst, VerilatedFstBuffer>;
|
||||
|
||||
private:
|
||||
friend Buffer; // Give the buffer access to the private bits
|
||||
friend VerilatedFstBuffer; // Give the buffer access to the private bits
|
||||
|
||||
//=========================================================================
|
||||
// FST specific internals
|
||||
|
||||
void* m_fst;
|
||||
void* m_fst = nullptr;
|
||||
std::map<uint32_t, fstHandle> m_code2symbol;
|
||||
std::map<int, fstEnumHandle> m_local2fstdtype;
|
||||
std::list<std::string> m_curScope;
|
||||
fstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array
|
||||
char* m_strbuf = nullptr; // String buffer long enough to hold maxBits() chars
|
||||
char* m_strbufp = nullptr; // String buffer long enough to hold maxBits() chars
|
||||
|
||||
bool m_useFstWriterThread = false; // Whether to use the separate FST writer thread
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFst);
|
||||
@@ -65,15 +67,18 @@ protected:
|
||||
// Implementation of VerilatedTrace interface
|
||||
|
||||
// Called when the trace moves forward to a new time point
|
||||
virtual void emitTimeChange(uint64_t timeui) override;
|
||||
void emitTimeChange(uint64_t timeui) override;
|
||||
|
||||
// Hooks called from VerilatedTrace
|
||||
virtual bool preFullDump() override { return isOpen(); }
|
||||
virtual bool preChangeDump() override { return isOpen(); }
|
||||
bool preFullDump() override { return isOpen(); }
|
||||
bool preChangeDump() override { return isOpen(); }
|
||||
|
||||
// Trace buffer management
|
||||
virtual VerilatedFstBuffer* getTraceBuffer() override;
|
||||
virtual void commitTraceBuffer(VerilatedFstBuffer*) override;
|
||||
Buffer* getTraceBuffer() override;
|
||||
void commitTraceBuffer(Buffer*) override;
|
||||
|
||||
// Configure sub-class
|
||||
void configure(const VerilatedTraceConfig&) override;
|
||||
|
||||
public:
|
||||
//=========================================================================
|
||||
@@ -96,6 +101,8 @@ public:
|
||||
//=========================================================================
|
||||
// Internal interface to Verilator generated code
|
||||
|
||||
void declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
void declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
void declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
@@ -113,46 +120,57 @@ public:
|
||||
|
||||
#ifndef DOXYGEN
|
||||
// Declare specialization here as it's used in VerilatedFstC just below
|
||||
template <> void VerilatedFst::Super::dump(uint64_t time);
|
||||
template <> void VerilatedFst::Super::set_time_unit(const char* unitp);
|
||||
template <> void VerilatedFst::Super::set_time_unit(const std::string& unit);
|
||||
template <> void VerilatedFst::Super::set_time_resolution(const char* unitp);
|
||||
template <> void VerilatedFst::Super::set_time_resolution(const std::string& unit);
|
||||
template <> void VerilatedFst::Super::dumpvars(int level, const std::string& hier);
|
||||
template <>
|
||||
void VerilatedFst::Super::dump(uint64_t time);
|
||||
template <>
|
||||
void VerilatedFst::Super::set_time_unit(const char* unitp);
|
||||
template <>
|
||||
void VerilatedFst::Super::set_time_unit(const std::string& unit);
|
||||
template <>
|
||||
void VerilatedFst::Super::set_time_resolution(const char* unitp);
|
||||
template <>
|
||||
void VerilatedFst::Super::set_time_resolution(const std::string& unit);
|
||||
template <>
|
||||
void VerilatedFst::Super::dumpvars(int level, const std::string& hier);
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedFstBuffer
|
||||
|
||||
class VerilatedFstBuffer final : public VerilatedTraceBuffer<VerilatedFst, VerilatedFstBuffer> {
|
||||
class VerilatedFstBuffer VL_NOT_FINAL {
|
||||
// Give the trace file access to the private bits
|
||||
friend VerilatedFst;
|
||||
friend VerilatedFst::Super;
|
||||
friend VerilatedFst::Buffer;
|
||||
friend VerilatedFst::OffloadBuffer;
|
||||
|
||||
VerilatedFst& m_owner; // Trace file owning this buffer. Required by subclasses.
|
||||
|
||||
// The FST file handle
|
||||
void* const m_fst = m_owner.m_fst;
|
||||
// code to fstHande map, as an array
|
||||
const fstHandle* const m_symbolp = m_owner.m_symbolp;
|
||||
// String buffer long enough to hold maxBits() chars
|
||||
char* const m_strbuf = m_owner.m_strbuf;
|
||||
char* const m_strbufp = m_owner.m_strbufp;
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
explicit VerilatedFstBuffer(VerilatedFst& owner);
|
||||
~VerilatedFstBuffer() = default;
|
||||
explicit VerilatedFstBuffer(VerilatedFst& owner)
|
||||
: m_owner{owner} {}
|
||||
virtual ~VerilatedFstBuffer() = default;
|
||||
|
||||
//=========================================================================
|
||||
// Implementation of VerilatedTraceBuffer interface
|
||||
|
||||
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
|
||||
// called from only one place (the full* methods), so always inline them.
|
||||
VL_ATTR_ALWINLINE inline void emitBit(uint32_t code, CData newval);
|
||||
VL_ATTR_ALWINLINE inline void emitCData(uint32_t code, CData newval, int bits);
|
||||
VL_ATTR_ALWINLINE inline void emitSData(uint32_t code, SData newval, int bits);
|
||||
VL_ATTR_ALWINLINE inline void emitIData(uint32_t code, IData newval, int bits);
|
||||
VL_ATTR_ALWINLINE inline void emitQData(uint32_t code, QData newval, int bits);
|
||||
VL_ATTR_ALWINLINE inline void emitWData(uint32_t code, const WData* newvalp, int bits);
|
||||
VL_ATTR_ALWINLINE inline void emitDouble(uint32_t code, double newval);
|
||||
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent 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 emitSData(uint32_t code, SData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitIData(uint32_t code, IData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitQData(uint32_t code, QData newval, int bits);
|
||||
VL_ATTR_ALWINLINE void emitWData(uint32_t code, const WData* newvalp, int bits);
|
||||
VL_ATTR_ALWINLINE void emitDouble(uint32_t code, double newval);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -217,7 +235,7 @@ public:
|
||||
}
|
||||
|
||||
// Internal class access
|
||||
inline VerilatedFst* spTrace() { return &m_sptrace; }
|
||||
VerilatedFst* spTrace() { return &m_sptrace; }
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
||||
@@ -14,82 +14,11 @@
|
||||
/// \file
|
||||
/// \brief Verilated tracing in FST for SystemC implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all Verilated objects
|
||||
/// that use --sc --trace-fst.
|
||||
///
|
||||
/// Use "verilator --sc --trace-fst" to add this to the Makefile for the linker.
|
||||
/// This file is deprecated, only verilated_fst_sc.h is needed.
|
||||
/// It is provided only for backward compatibility with user's linker scripts.
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated_fst_sc.h"
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
|
||||
void VerilatedFstSc::open(const char* filename) {
|
||||
if (!sc_core::sc_get_curr_simcontext()->elaboration_done()) {
|
||||
vl_fatal(__FILE__, __LINE__, "VerilatedFstSc",
|
||||
("%Error: VerilatedFstSc::open(\"" + std::string(filename)
|
||||
+ "\") is called before sc_core::sc_start(). "
|
||||
"Run sc_core::sc_start(sc_core::SC_ZERO_TIME) before opening a wave file.")
|
||||
.c_str());
|
||||
}
|
||||
VerilatedFstC::open(filename);
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// SystemC 2.1.v1
|
||||
// cppcheck-suppress unusedFunction
|
||||
void VerilatedFstSc::write_comment(const std::string&) {}
|
||||
void VerilatedFstSc::trace(const unsigned int&, const std::string&, const char**) {}
|
||||
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedFstSc::trace(const tp& object, const std::string& name) {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedFstSc::trace(const tp& object, const std::string& name, int width) {}
|
||||
|
||||
// clang-format off
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
#ifdef VL_NO_LEGACY
|
||||
#error "verilated_fst_sc.cpp is deprecated; verilated_fst_sc.h is self-sufficient"
|
||||
#endif
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_logic )
|
||||
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_B( sc_dt::int64 )
|
||||
DECL_TRACE_METHOD_B( sc_dt::uint64 )
|
||||
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_unsigned )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
// clang-format on
|
||||
|
||||
#undef DECL_TRACE_METHOD_A
|
||||
#undef DECL_TRACE_METHOD_B
|
||||
|
||||
//********************************************************************
|
||||
|
||||
+38
-27
@@ -10,7 +10,7 @@
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator tracing in FST format for SystemC header
|
||||
/// \brief Verilated tracing in FST format for SystemC header
|
||||
///
|
||||
/// User wrapper code should use this header when creating FST SystemC
|
||||
/// traces.
|
||||
@@ -19,69 +19,82 @@
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#ifndef _VERILATED_FST_SC_H_
|
||||
#define _VERILATED_FST_SC_H_ 1
|
||||
#ifndef VERILATOR_VERILATED_VCD_SC_H_
|
||||
#define VERILATOR_VERILATED_VCD_SC_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated_sc.h"
|
||||
|
||||
#include "verilated_fst_c.h"
|
||||
#include "verilated_sc.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedFstSc
|
||||
///
|
||||
/// This class is passed to the SystemC simulation kernel, just like a
|
||||
/// documented SystemC trace format.
|
||||
/// Class representing a Verilator-friendly FST trace format registered
|
||||
/// with the SystemC simulation kernel, just like a SystemC-documented
|
||||
/// trace format.
|
||||
|
||||
class VerilatedFstSc final : sc_trace_file, public VerilatedFstC {
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFstSc);
|
||||
|
||||
public:
|
||||
/// Construct a SC trace object, and register with the SystemC kernel
|
||||
VerilatedFstSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
// We want to avoid a depreciated warning, but still be back compatible.
|
||||
// Turning off the message just for this still results in an
|
||||
// annoying "to turn off" message.
|
||||
const sc_time t1sec(1, SC_SEC);
|
||||
const sc_time t1sec{1, SC_SEC};
|
||||
if (t1sec.to_default_time_units() != 0) {
|
||||
const sc_time tunits(1.0 / t1sec.to_default_time_units(), SC_SEC);
|
||||
const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC};
|
||||
spTrace()->set_time_unit(tunits.to_string());
|
||||
}
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
}
|
||||
virtual ~VerilatedFstSc() { close(); }
|
||||
/// Destruct, flush, and close the dump
|
||||
~VerilatedFstSc() override { close(); }
|
||||
|
||||
// METHODS
|
||||
/// Called by SystemC simulate()
|
||||
virtual void cycle(bool delta_cycle) {
|
||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||
// METHODS - for SC kernel
|
||||
// Called by SystemC simulate()
|
||||
void cycle(bool delta_cycle) override {
|
||||
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
|
||||
}
|
||||
|
||||
// Override VerilatedFstC. Must be called after starting simulation.
|
||||
virtual void open(const char* filename) /*override*/ VL_MT_SAFE;
|
||||
// Note: this is not a virtual function in the base class, so no 'override'
|
||||
virtual void open(const char* filename) VL_MT_SAFE {
|
||||
if (VL_UNLIKELY(!sc_core::sc_get_curr_simcontext()->elaboration_done())) {
|
||||
Verilated::scTraceBeforeElaborationError();
|
||||
}
|
||||
VerilatedFstC::open(filename);
|
||||
}
|
||||
|
||||
private:
|
||||
/// Fake outs for linker
|
||||
// METHODS - Fake outs for linker
|
||||
|
||||
#ifdef NC_SYSTEMC
|
||||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
virtual void set_time_unit(int exponent10_seconds) {} // deprecated
|
||||
void set_time_unit(int exponent10_seconds) override {} // deprecated
|
||||
#endif
|
||||
virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE
|
||||
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
|
||||
|
||||
//--------------------------------------------------
|
||||
// SystemC 2.1.v1
|
||||
#define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name);
|
||||
//--------------------------------------------------
|
||||
// SystemC 2.1.v1
|
||||
|
||||
void write_comment(const std::string&) override {}
|
||||
void trace(const unsigned int&, const std::string&, const char**) override {}
|
||||
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void trace(const tp& object, const std::string& name) override {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace(const tp& object, const std::string& name, int width);
|
||||
|
||||
virtual void write_comment(const std::string&);
|
||||
virtual void trace(const unsigned int&, const std::string&, const char**);
|
||||
void trace(const tp& object, const std::string& name, int width) override {}
|
||||
|
||||
// clang-format off
|
||||
// Formatting matches that of sc_trace.h
|
||||
// LCOV_EXCL_START
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
@@ -95,9 +108,6 @@ private:
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
@@ -119,6 +129,7 @@ private:
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
// LCOV_EXCL_STOP
|
||||
// clang-format on
|
||||
|
||||
#undef DECL_TRACE_METHOD_A
|
||||
|
||||
+110
-95
@@ -37,24 +37,26 @@
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_FINISH.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
|
||||
extern void vl_finish(const char* filename, int linenum, const char* hier);
|
||||
extern void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE;
|
||||
|
||||
/// Routine to call for $stop and non-fatal error
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_STOP.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
|
||||
extern void vl_stop(const char* filename, int linenum, const char* hier);
|
||||
extern void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE;
|
||||
|
||||
/// Routine to call for fatal messages
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_FATAL.
|
||||
/// This code does not have to be thread safe.
|
||||
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
|
||||
extern void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg);
|
||||
extern void vl_fatal(const char* filename, int linenum, const char* hier,
|
||||
const char* msg) VL_MT_UNSAFE;
|
||||
|
||||
/// Routine to call for warning messages
|
||||
/// User code may wish to replace this function, to do so, define VL_USER_WARN.
|
||||
/// This code does not have to be thread safe.
|
||||
extern void vl_warn(const char* filename, int linenum, const char* hier, const char* msg);
|
||||
extern void vl_warn(const char* filename, int linenum, const char* hier,
|
||||
const char* msg) VL_MT_UNSAFE;
|
||||
|
||||
//=========================================================================
|
||||
// Extern functions -- Slow path
|
||||
@@ -73,11 +75,7 @@ extern void VL_WARN_MT(const char* filename, int linenum, const char* hier,
|
||||
|
||||
// clang-format off
|
||||
/// Print a string, multithread safe. Eventually VL_PRINTF will get called.
|
||||
#ifdef VL_THREADED
|
||||
extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
||||
#else
|
||||
# define VL_PRINTF_MT VL_PRINTF // The following parens will take care of themselves
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
/// Print a debug message from internals with standard prefix, with printf style format
|
||||
@@ -86,7 +84,7 @@ extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
|
||||
// EMIT_RULE: VL_RANDOM: oclean=dirty
|
||||
inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); }
|
||||
inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); }
|
||||
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp);
|
||||
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||
extern IData VL_RANDOM_SEEDED_II(IData& seedr) VL_MT_SAFE;
|
||||
extern IData VL_URANDOM_SEEDED_II(IData seed) VL_MT_SAFE;
|
||||
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
|
||||
@@ -104,50 +102,52 @@ inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
|
||||
|
||||
// These are init time only, so slow is fine
|
||||
/// Random reset a signal of given width
|
||||
extern IData VL_RAND_RESET_I(int obits);
|
||||
extern IData VL_RAND_RESET_I(int obits) VL_MT_SAFE;
|
||||
/// Random reset a signal of given width
|
||||
extern QData VL_RAND_RESET_Q(int obits);
|
||||
extern QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE;
|
||||
/// Random reset a signal of given width
|
||||
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp);
|
||||
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||
/// Zero reset a signal (slow - else use VL_ZERO_W)
|
||||
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp);
|
||||
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
|
||||
|
||||
extern void VL_PRINTTIMESCALE(const char* namep, const char* timeunitp,
|
||||
const VerilatedContext* contextp) VL_MT_SAFE;
|
||||
|
||||
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP const lwp, WDataInP const rwp,
|
||||
bool is_modulus);
|
||||
bool is_modulus) VL_MT_SAFE;
|
||||
|
||||
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
|
||||
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE;
|
||||
|
||||
extern void VL_FFLUSH_I(IData fdi);
|
||||
extern IData VL_FSEEK_I(IData fdi, IData offset, IData origin);
|
||||
extern IData VL_FTELL_I(IData fdi);
|
||||
extern void VL_FCLOSE_I(IData fdi);
|
||||
extern void VL_FFLUSH_I(IData fdi) VL_MT_SAFE;
|
||||
extern IData VL_FSEEK_I(IData fdi, IData offset, IData origin) VL_MT_SAFE;
|
||||
extern IData VL_FTELL_I(IData fdi) VL_MT_SAFE;
|
||||
extern void VL_FCLOSE_I(IData fdi) VL_MT_SAFE;
|
||||
|
||||
extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi,
|
||||
IData start, IData count);
|
||||
IData start, IData count) VL_MT_SAFE;
|
||||
|
||||
extern void VL_WRITEF(const char* formatp, ...);
|
||||
extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
|
||||
extern void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE;
|
||||
|
||||
extern IData VL_FSCANF_IX(IData fpi, const char* formatp, ...);
|
||||
extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...);
|
||||
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...);
|
||||
extern IData VL_SSCANF_IWX(int lbits, WDataInP const lwp, const char* formatp, ...);
|
||||
extern IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern IData VL_SSCANF_IWX(int lbits, WDataInP const lwp, const char* formatp, ...) VL_MT_SAFE;
|
||||
|
||||
extern void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE;
|
||||
|
||||
extern IData VL_SYSTEM_IW(int lhswords, WDataInP const lhsp);
|
||||
extern IData VL_SYSTEM_IQ(QData lhs);
|
||||
extern void VL_STACKTRACE() VL_MT_SAFE;
|
||||
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_IQ(QData lhs) VL_MT_SAFE;
|
||||
inline IData VL_SYSTEM_II(IData lhs) VL_MT_SAFE { return VL_SYSTEM_IQ(lhs); }
|
||||
|
||||
extern IData VL_TESTPLUSARGS_I(const char* formatp);
|
||||
extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
|
||||
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
|
||||
|
||||
//=========================================================================
|
||||
// Base macros
|
||||
@@ -216,14 +216,14 @@ static inline double VL_ITOR_D_Q(int, QData lhs) VL_PURE {
|
||||
return static_cast<double>(static_cast<uint64_t>(lhs));
|
||||
}
|
||||
// Return double from lhs (numeric) signed
|
||||
double VL_ISTOR_D_W(int lbits, WDataInP const lwp) VL_PURE;
|
||||
static inline double VL_ISTOR_D_I(int lbits, IData lhs) VL_PURE {
|
||||
double VL_ISTOR_D_W(int lbits, WDataInP const lwp) VL_MT_SAFE;
|
||||
static inline double VL_ISTOR_D_I(int lbits, IData lhs) VL_MT_SAFE {
|
||||
if (lbits == 32) return static_cast<double>(static_cast<int32_t>(lhs));
|
||||
VlWide<VL_WQ_WORDS_E> lwp;
|
||||
VL_SET_WI(lwp, lhs);
|
||||
return VL_ISTOR_D_W(lbits, lwp);
|
||||
}
|
||||
static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_PURE {
|
||||
static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_MT_SAFE {
|
||||
if (lbits == 64) return static_cast<double>(static_cast<int64_t>(lhs));
|
||||
VlWide<VL_WQ_WORDS_E> lwp;
|
||||
VL_SET_WQ(lwp, lhs);
|
||||
@@ -251,56 +251,39 @@ static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE {
|
||||
}
|
||||
|
||||
// Debugging prints
|
||||
extern void _vl_debug_print_w(int lbits, WDataInP const iwp);
|
||||
extern void _vl_debug_print_w(int lbits, WDataInP const iwp) VL_MT_SAFE;
|
||||
|
||||
//=========================================================================
|
||||
// Pli macros
|
||||
|
||||
extern int VL_TIME_STR_CONVERT(const char* strp) VL_PURE;
|
||||
|
||||
// These are deprecated and used only to establish the default precision/units.
|
||||
// Use Verilator timescale-override for better control.
|
||||
// clang-format off
|
||||
#ifndef VL_TIME_PRECISION
|
||||
# ifdef VL_TIME_PRECISION_STR
|
||||
# define VL_TIME_PRECISION VL_TIME_STR_CONVERT(VL_STRINGIFY(VL_TIME_PRECISION_STR))
|
||||
# else
|
||||
# define VL_TIME_PRECISION (-12) ///< Timescale default units if not in Verilog - picoseconds
|
||||
# endif
|
||||
#endif
|
||||
#ifndef VL_TIME_UNIT
|
||||
# ifdef VL_TIME_UNIT_STR
|
||||
# define VL_TIME_UNIT VL_TIME_STR_CONVERT(VL_STRINGIFY(VL_TIME_PRECISION_STR))
|
||||
# else
|
||||
# define VL_TIME_UNIT (-12) ///< Timescale default units if not in Verilog - picoseconds
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(SYSTEMC_VERSION)
|
||||
/// Return current simulation time
|
||||
// Already defined: extern sc_time sc_time_stamp();
|
||||
inline uint64_t vl_time_stamp64() { return sc_time_stamp().value(); }
|
||||
inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_time_stamp().value(); }
|
||||
#else // Non-SystemC
|
||||
# if !defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY)
|
||||
# ifdef VL_TIME_STAMP64
|
||||
// vl_time_stamp64() may be optionally defined by the user to return time.
|
||||
// On MSVC++ weak symbols are not supported so must be declared, or define
|
||||
// VL_TIME_CONTEXT.
|
||||
extern uint64_t vl_time_stamp64() VL_ATTR_WEAK;
|
||||
extern uint64_t vl_time_stamp64() VL_ATTR_WEAK VL_MT_SAFE;
|
||||
# else
|
||||
// sc_time_stamp() may be optionally defined by the user to return time.
|
||||
// On MSVC++ weak symbols are not supported so must be declared, or define
|
||||
// VL_TIME_CONTEXT.
|
||||
extern double sc_time_stamp() VL_ATTR_WEAK; // Verilator 4.032 and newer
|
||||
inline uint64_t vl_time_stamp64() {
|
||||
extern double sc_time_stamp() VL_ATTR_WEAK VL_MT_SAFE; // Verilator 4.032 and newer
|
||||
inline uint64_t vl_time_stamp64() VL_MT_SAFE {
|
||||
// clang9.0.1 requires & although we really do want the weak symbol value
|
||||
// cppcheck-suppress duplicateValueTernary
|
||||
return VL_LIKELY(&sc_time_stamp) ? static_cast<uint64_t>(sc_time_stamp()) : 0;
|
||||
}
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
inline uint64_t VerilatedContext::time() const VL_MT_SAFE {
|
||||
uint64_t VerilatedContext::time() const VL_MT_SAFE {
|
||||
// When using non-default context, fastest path is return time
|
||||
if (VL_LIKELY(m_s.m_time)) return m_s.m_time;
|
||||
#if defined(SYSTEMC_VERSION) || (!defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY))
|
||||
@@ -466,10 +449,17 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
|
||||
{ \
|
||||
const int words = VL_WORDS_I(obits); \
|
||||
sc_biguint<(obits)> _butemp = (svar).read(); \
|
||||
for (int i = 0; i < words; ++i) { \
|
||||
int msb = ((i + 1) * VL_IDATASIZE) - 1; \
|
||||
msb = (msb >= (obits)) ? ((obits)-1) : msb; \
|
||||
(owp)[i] = _butemp.range(msb, i * VL_IDATASIZE).to_uint(); \
|
||||
uint32_t* chunkp = _butemp.get_raw(); \
|
||||
int32_t lsb = 0; \
|
||||
while (lsb < obits - BITS_PER_DIGIT) { \
|
||||
const uint32_t data = *chunkp; \
|
||||
++chunkp; \
|
||||
_vl_insert_WI(owp.data(), data, lsb + BITS_PER_DIGIT - 1, lsb); \
|
||||
lsb += BITS_PER_DIGIT; \
|
||||
} \
|
||||
if (lsb < obits) { \
|
||||
const uint32_t msb_data = *chunkp; \
|
||||
_vl_insert_WI(owp.data(), msb_data, obits - 1, lsb); \
|
||||
} \
|
||||
(owp)[words - 1] &= VL_MASK_E(obits); \
|
||||
}
|
||||
@@ -510,13 +500,23 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
|
||||
{ (svar).write(rd); }
|
||||
#define VL_ASSIGN_SBQ(obits, svar, 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) \
|
||||
{ \
|
||||
sc_biguint<(obits)> _butemp; \
|
||||
for (int i = 0; i < VL_WORDS_I(obits); ++i) { \
|
||||
int msb = ((i + 1) * VL_IDATASIZE) - 1; \
|
||||
msb = (msb >= (obits)) ? ((obits)-1) : msb; \
|
||||
_butemp.range(msb, i* VL_IDATASIZE) = (rwp)[i]; \
|
||||
int32_t lsb = 0; \
|
||||
uint32_t* chunkp = _butemp.get_raw(); \
|
||||
while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \
|
||||
static_assert(std::is_same<IData, EData>::value, "IData and EData missmatch"); \
|
||||
const uint32_t data = VL_SEL_IWII(lsb + VL_SC_BITS_PER_DIGIT + 1, (rwp).data(), lsb, \
|
||||
VL_SC_BITS_PER_DIGIT); \
|
||||
*chunkp = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \
|
||||
++chunkp; \
|
||||
lsb += VL_SC_BITS_PER_DIGIT; \
|
||||
} \
|
||||
if (lsb < (obits)) { \
|
||||
const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \
|
||||
*chunkp = msb_data & VL_MASK_E((obits)-lsb); \
|
||||
} \
|
||||
(svar).write(_butemp); \
|
||||
}
|
||||
@@ -591,18 +591,19 @@ static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp,
|
||||
// EMIT_RULE: VL_REDAND: oclean=clean; lclean==clean; obits=1;
|
||||
#define VL_REDAND_II(lbits, lhs) ((lhs) == VL_MASK_I(lbits))
|
||||
#define VL_REDAND_IQ(lbits, lhs) ((lhs) == VL_MASK_Q(lbits))
|
||||
static inline IData VL_REDAND_IW(int lbits, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline IData VL_REDAND_IW(int lbits, WDataInP const lwp) VL_PURE {
|
||||
const int words = VL_WORDS_I(lbits);
|
||||
EData combine = lwp[0];
|
||||
for (int i = 1; i < words - 1; ++i) combine &= lwp[i];
|
||||
combine &= ~VL_MASK_E(lbits) | lwp[words - 1];
|
||||
// cppcheck-has-bug-suppress knownConditionTrueFalse
|
||||
return ((~combine) == 0);
|
||||
}
|
||||
|
||||
// EMIT_RULE: VL_REDOR: oclean=clean; lclean==clean; obits=1;
|
||||
#define VL_REDOR_I(lhs) ((lhs) != 0)
|
||||
#define VL_REDOR_Q(lhs) ((lhs) != 0)
|
||||
static inline IData VL_REDOR_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline IData VL_REDOR_W(int words, WDataInP const lwp) VL_PURE {
|
||||
EData equal = 0;
|
||||
for (int i = 0; i < words; ++i) equal |= lwp[i];
|
||||
return (equal != 0);
|
||||
@@ -669,7 +670,7 @@ static inline IData VL_REDXOR_64(QData r) VL_PURE {
|
||||
return static_cast<IData>(r);
|
||||
#endif
|
||||
}
|
||||
static inline IData VL_REDXOR_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline IData VL_REDXOR_W(int words, WDataInP const lwp) VL_PURE {
|
||||
EData r = lwp[0];
|
||||
for (int i = 1; i < words; ++i) r ^= lwp[i];
|
||||
return VL_REDXOR_32(r);
|
||||
@@ -688,7 +689,7 @@ static inline IData VL_COUNTONES_Q(QData lhs) VL_PURE {
|
||||
return VL_COUNTONES_I(static_cast<IData>(lhs)) + VL_COUNTONES_I(static_cast<IData>(lhs >> 32));
|
||||
}
|
||||
#define VL_COUNTONES_E VL_COUNTONES_I
|
||||
static inline IData VL_COUNTONES_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline IData VL_COUNTONES_W(int words, WDataInP const lwp) VL_PURE {
|
||||
EData r = 0;
|
||||
for (int i = 0; i < words; ++i) r += VL_COUNTONES_E(lwp[i]);
|
||||
return r;
|
||||
@@ -730,7 +731,7 @@ static inline IData VL_ONEHOT_I(IData lhs) VL_PURE {
|
||||
static inline IData VL_ONEHOT_Q(QData lhs) VL_PURE {
|
||||
return (((lhs & (lhs - 1)) == 0) & (lhs != 0));
|
||||
}
|
||||
static inline IData VL_ONEHOT_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline IData VL_ONEHOT_W(int words, WDataInP const lwp) VL_PURE {
|
||||
EData one = 0;
|
||||
for (int i = 0; (i < words); ++i) {
|
||||
if (lwp[i]) {
|
||||
@@ -744,7 +745,7 @@ static inline IData VL_ONEHOT_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
|
||||
static inline IData VL_ONEHOT0_I(IData lhs) VL_PURE { return ((lhs & (lhs - 1)) == 0); }
|
||||
static inline IData VL_ONEHOT0_Q(QData lhs) VL_PURE { return ((lhs & (lhs - 1)) == 0); }
|
||||
static inline IData VL_ONEHOT0_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline IData VL_ONEHOT0_W(int words, WDataInP const lwp) VL_PURE {
|
||||
bool one = false;
|
||||
for (int i = 0; (i < words); ++i) {
|
||||
if (lwp[i]) {
|
||||
@@ -771,7 +772,7 @@ static inline IData VL_CLOG2_Q(QData lhs) VL_PURE {
|
||||
for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL;
|
||||
return shifts;
|
||||
}
|
||||
static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_PURE {
|
||||
const EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1;
|
||||
for (int i = words - 1; i >= 0; --i) {
|
||||
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
|
||||
@@ -786,7 +787,7 @@ static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP const lwp) VL_MT_SAFE {
|
||||
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP const lwp) VL_PURE {
|
||||
// MSB set bit plus one; similar to FLS. 0=value is zero
|
||||
for (int i = words - 1; i >= 0; --i) {
|
||||
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
|
||||
@@ -815,7 +816,7 @@ static inline WDataOutP VL_OR_W(int words, WDataOutP owp, WDataInP const lwp,
|
||||
return owp;
|
||||
}
|
||||
// EMIT_RULE: VL_CHANGEXOR: oclean=1; obits=32; lbits==rbits;
|
||||
static inline IData VL_CHANGEXOR_W(int words, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
|
||||
static inline IData VL_CHANGEXOR_W(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE {
|
||||
IData od = 0;
|
||||
for (int i = 0; (i < words); ++i) od |= (lwp[i] ^ rwp[i]);
|
||||
return od;
|
||||
@@ -848,14 +849,14 @@ static inline WDataOutP VL_NOT_W(int words, WDataOutP owp, WDataInP const lwp) V
|
||||
#define VL_GTE_W(words, lwp, rwp) (_vl_cmp_w(words, lwp, rwp) >= 0)
|
||||
|
||||
// Output clean, <lhs> AND <rhs> MUST BE CLEAN
|
||||
static inline IData VL_EQ_W(int words, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
|
||||
static inline IData VL_EQ_W(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE {
|
||||
EData nequal = 0;
|
||||
for (int i = 0; (i < words); ++i) nequal |= (lwp[i] ^ rwp[i]);
|
||||
return (nequal == 0);
|
||||
}
|
||||
|
||||
// Internal usage
|
||||
static inline int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
|
||||
static inline int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE {
|
||||
for (int i = words - 1; i >= 0; --i) {
|
||||
if (lwp[i] > rwp[i]) return 1;
|
||||
if (lwp[i] < rwp[i]) return -1;
|
||||
@@ -914,7 +915,7 @@ static inline IData VL_LTES_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
|
||||
return lhs_signed <= rhs_signed;
|
||||
}
|
||||
|
||||
static inline int _vl_cmps_w(int lbits, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
|
||||
static inline int _vl_cmps_w(int lbits, WDataInP const lwp, WDataInP const rwp) VL_PURE {
|
||||
const int words = VL_WORDS_I(lbits);
|
||||
int i = words - 1;
|
||||
// We need to flip sense if negative comparison
|
||||
@@ -930,7 +931,7 @@ static inline int _vl_cmps_w(int lbits, WDataInP const lwp, WDataInP const rwp)
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Math
|
||||
// Expressions
|
||||
|
||||
// Output NOT clean
|
||||
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
|
||||
@@ -1027,12 +1028,14 @@ static inline WDataOutP VL_MULS_WWW(int lbits, WDataOutP owp, WDataInP const lwp
|
||||
if (lneg) { // Negate lhs
|
||||
lwusp = lwstore;
|
||||
VL_NEGATE_W(words, lwstore, lwp);
|
||||
// cppcheck-has-bug-suppress unreadVariable
|
||||
lwstore[words - 1] &= VL_MASK_E(lbits); // Clean it
|
||||
}
|
||||
const EData rneg = VL_SIGN_E(lbits, rwp[words - 1]);
|
||||
if (rneg) { // Negate rhs
|
||||
rwusp = rwstore;
|
||||
VL_NEGATE_W(words, rwstore, rwp);
|
||||
// cppcheck-has-bug-suppress unreadVariable
|
||||
rwstore[words - 1] &= VL_MASK_E(lbits); // Clean it
|
||||
}
|
||||
VL_MUL_W(words, owp, lwusp, rwusp);
|
||||
@@ -1157,9 +1160,10 @@ static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) VL_PUR
|
||||
return out;
|
||||
}
|
||||
WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp,
|
||||
WDataInP const rwp);
|
||||
WDataOutP VL_POW_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp, QData rhs);
|
||||
QData VL_POW_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp);
|
||||
WDataInP const rwp) VL_MT_SAFE;
|
||||
WDataOutP VL_POW_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp,
|
||||
QData rhs) VL_MT_SAFE;
|
||||
QData VL_POW_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp) VL_MT_SAFE;
|
||||
|
||||
#define VL_POWSS_IIQ(obits, lbits, rbits, lhs, rhs, lsign, rsign) \
|
||||
VL_POWSS_QQQ(obits, lbits, rbits, lhs, rhs, lsign, rsign)
|
||||
@@ -1211,11 +1215,11 @@ static inline QData VL_POWSS_QQQ(int obits, int, int rbits, QData lhs, QData rhs
|
||||
return VL_POW_QQQ(obits, rbits, rbits, lhs, rhs);
|
||||
}
|
||||
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp,
|
||||
WDataInP const rwp, bool lsign, bool rsign);
|
||||
WDataInP const rwp, bool lsign, bool rsign) VL_MT_SAFE;
|
||||
WDataOutP VL_POWSS_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp, QData rhs,
|
||||
bool lsign, bool rsign);
|
||||
bool lsign, bool rsign) VL_MT_SAFE;
|
||||
QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp, bool lsign,
|
||||
bool rsign);
|
||||
bool rsign) VL_MT_SAFE;
|
||||
|
||||
//===================================================================
|
||||
// Concat/replication
|
||||
@@ -1393,7 +1397,7 @@ static inline IData VL_STREAML_FAST_III(int lbits, IData ld, IData rd_log2) VL_P
|
||||
//
|
||||
// If lbits is not a multiple of the slice size (i.e., lbits % rd != 0),
|
||||
// then we end up with a "gap" in our reversed result. For example, if we
|
||||
// have a 5-bit Verlilog signal (lbits=5) in an 8-bit C data type:
|
||||
// have a 5-bit Verilog signal (lbits=5) in an 8-bit C data type:
|
||||
//
|
||||
// ld = ---43210
|
||||
//
|
||||
@@ -1918,7 +1922,7 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataIn
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Math needing insert/select
|
||||
// Expressions needing insert/select
|
||||
|
||||
// Return QData from double (numeric)
|
||||
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
|
||||
@@ -1942,7 +1946,7 @@ static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {
|
||||
static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE {
|
||||
return static_cast<IData>(VL_RTOIROUND_Q_D(lhs));
|
||||
}
|
||||
static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) VL_PURE {
|
||||
static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) VL_MT_SAFE {
|
||||
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
|
||||
// This does not need to support subnormals as they are sub-integral
|
||||
lhs = VL_ROUND(lhs);
|
||||
@@ -2152,7 +2156,18 @@ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool igno
|
||||
|
||||
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
|
||||
|
||||
extern IData VL_FGETS_NI(std::string& dest, IData fpi);
|
||||
extern IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE;
|
||||
|
||||
//======================================================================
|
||||
// Dist functions
|
||||
|
||||
extern IData VL_DIST_CHI_SQUARE(IData& seedr, IData udeg_of_free) VL_MT_SAFE;
|
||||
extern IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE;
|
||||
extern IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE;
|
||||
extern IData VL_DIST_NORMAL(IData& seedr, IData umean, IData udeviation) VL_MT_SAFE;
|
||||
extern IData VL_DIST_POISSON(IData& seedr, IData umean) VL_MT_SAFE;
|
||||
extern IData VL_DIST_T(IData& seedr, IData udeg_of_free) VL_MT_SAFE;
|
||||
extern IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE;
|
||||
|
||||
//======================================================================
|
||||
// Conversion functions
|
||||
@@ -2184,8 +2199,8 @@ inline std::string VL_REPLICATEN_NNI(const std::string& lhs, IData rep) VL_PURE
|
||||
}
|
||||
|
||||
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
|
||||
extern std::string VL_TOLOWER_NN(const std::string& ld);
|
||||
extern std::string VL_TOUPPER_NN(const std::string& ld);
|
||||
extern std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE;
|
||||
extern std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE;
|
||||
|
||||
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
|
||||
extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE;
|
||||
|
||||
+28
-34
@@ -41,10 +41,8 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#ifdef VL_THREADED
|
||||
# include <functional>
|
||||
# include <queue>
|
||||
#endif
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
// clang-format on
|
||||
|
||||
class VerilatedScope;
|
||||
@@ -52,7 +50,6 @@ class VerilatedScope;
|
||||
//======================================================================
|
||||
// Threaded message passing
|
||||
|
||||
#ifdef VL_THREADED
|
||||
// Message, enqueued on an mtask, and consumed on the main eval thread
|
||||
class VerilatedMsg final {
|
||||
public:
|
||||
@@ -143,17 +140,16 @@ class VerilatedThreadMsgQueue final {
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedThreadMsgQueue() {}
|
||||
~VerilatedThreadMsgQueue() {
|
||||
// The only call of this with a non-empty queue is a fatal error.
|
||||
// So this does not flush the queue, as the destination queue is not known to this class.
|
||||
}
|
||||
VerilatedThreadMsgQueue() = default;
|
||||
~VerilatedThreadMsgQueue() = default;
|
||||
// The only call of destructor with a non-empty queue is a fatal error.
|
||||
// So this does not flush the queue, as the destination queue is not known to this class.
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
||||
// METHODS
|
||||
static VerilatedThreadMsgQueue& threadton() {
|
||||
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
||||
static thread_local VerilatedThreadMsgQueue t_s;
|
||||
return t_s;
|
||||
}
|
||||
|
||||
@@ -179,7 +175,6 @@ public:
|
||||
}
|
||||
}
|
||||
};
|
||||
#endif // VL_THREADED
|
||||
|
||||
// FILE* list constructed from a file-descriptor
|
||||
class VerilatedFpList final {
|
||||
@@ -188,11 +183,11 @@ class VerilatedFpList final {
|
||||
|
||||
public:
|
||||
using const_iterator = FILE* const*;
|
||||
explicit VerilatedFpList() {}
|
||||
explicit VerilatedFpList() = default;
|
||||
const_iterator begin() const { return m_fp; }
|
||||
const_iterator end() const { return m_fp + m_sz; }
|
||||
std::size_t size() const { return m_sz; }
|
||||
std::size_t capacity() const { return 31; }
|
||||
static std::size_t capacity() { return 31; }
|
||||
void push_back(FILE* fd) {
|
||||
if (VL_LIKELY(size() < capacity())) m_fp[m_sz++] = fd;
|
||||
}
|
||||
@@ -231,17 +226,16 @@ class VerilatedContextImp final : VerilatedContext {
|
||||
// Number incrementing on each reseed, 0=illegal
|
||||
int s_randSeedEpoch = 1; // Reads ok, wish had a VL_WRITE_GUARDED_BY(s_randMutex)
|
||||
};
|
||||
static Statics& s() {
|
||||
static Statics& s() VL_MT_SAFE {
|
||||
static Statics s_s;
|
||||
return s_s;
|
||||
}
|
||||
|
||||
private:
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS - no data can live here, use only VerilatedContext
|
||||
VerilatedContextImp() = delete;
|
||||
~VerilatedContextImp() = delete;
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - extending into VerilatedContext, call via impp()->
|
||||
|
||||
// Random seed handling
|
||||
@@ -272,13 +266,12 @@ public: // But only for verilated*.cpp
|
||||
std::string argPlusMatch(const char* prefixp) VL_MT_SAFE_EXCLUDES(m_argMutex);
|
||||
std::pair<int, char**> argc_argv() VL_MT_SAFE_EXCLUDES(m_argMutex);
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
// METHODS - scope name - INTERNAL only for verilated*.cpp
|
||||
void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE;
|
||||
void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE;
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - file IO
|
||||
// METHODS - file IO - INTERNAL only for verilated*.cpp
|
||||
|
||||
IData fdNewMcd(const char* filenamep) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
|
||||
const VerilatedLockGuard lock{m_fdMutex};
|
||||
if (m_fdFreeMct.empty()) return 0;
|
||||
@@ -298,7 +291,7 @@ public: // But only for verilated*.cpp
|
||||
const std::size_t start = std::max<std::size_t>(31UL + 1UL + 3UL, m_fdps.size());
|
||||
const std::size_t excess = 10;
|
||||
m_fdps.resize(start + excess);
|
||||
std::fill(m_fdps.begin() + start, m_fdps.end(), (FILE*)0);
|
||||
std::fill(m_fdps.begin() + start, m_fdps.end(), static_cast<FILE*>(nullptr));
|
||||
m_fdFree.resize(excess);
|
||||
for (std::size_t i = 0, id = start; i < m_fdFree.size(); ++i, ++id) {
|
||||
m_fdFree[i] = id;
|
||||
@@ -344,7 +337,7 @@ public: // But only for verilated*.cpp
|
||||
if (VL_UNLIKELY(idx <= 2)) return; // stdout/stdin/stderr
|
||||
if (VL_UNLIKELY(!m_fdps[idx])) return; // Already free
|
||||
std::fclose(m_fdps[idx]);
|
||||
m_fdps[idx] = (FILE*)0;
|
||||
m_fdps[idx] = nullptr;
|
||||
m_fdFree.push_back(idx);
|
||||
} else {
|
||||
// MCD case
|
||||
@@ -359,7 +352,7 @@ public: // But only for verilated*.cpp
|
||||
}
|
||||
}
|
||||
}
|
||||
inline FILE* fdToFp(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
|
||||
FILE* fdToFp(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) {
|
||||
const VerilatedLockGuard lock{m_fdMutex};
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
if (VL_UNLIKELY(fdlist.size() != 1)) return nullptr;
|
||||
@@ -369,6 +362,7 @@ public: // But only for verilated*.cpp
|
||||
private:
|
||||
VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(m_fdMutex) {
|
||||
VerilatedFpList fp;
|
||||
// cppverilator-suppress integerOverflow shiftTooManyBitsSigned
|
||||
if ((fdi & (1 << 31)) != 0) {
|
||||
// Non-MCD case
|
||||
const IData idx = fdi & VL_MASK_I(31);
|
||||
@@ -393,7 +387,9 @@ private:
|
||||
|
||||
protected:
|
||||
// METHODS - protected
|
||||
void commandArgsAddGuts(int argc, const char** argv);
|
||||
void commandArgsGuts(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex);
|
||||
void commandArgsAddGutsLock(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex);
|
||||
void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(m_argMutex);
|
||||
void commandArgVl(const std::string& arg);
|
||||
bool commandArgVlString(const std::string& arg, const std::string& prefix,
|
||||
std::string& valuer);
|
||||
@@ -447,7 +443,7 @@ protected:
|
||||
friend class Verilated;
|
||||
|
||||
// MEMBERS
|
||||
static VerilatedImpData& s() { // Singleton
|
||||
static VerilatedImpData& s() VL_MT_SAFE { // Singleton
|
||||
static VerilatedImpData s_s;
|
||||
return s_s;
|
||||
}
|
||||
@@ -464,13 +460,12 @@ public:
|
||||
// METHODS - debug
|
||||
static void versionDump() VL_MT_SAFE;
|
||||
|
||||
public:
|
||||
// METHODS - user scope tracking
|
||||
// We implement this as a single large map instead of one map per scope.
|
||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||
// As scopep's are pointers, this implicitly handles multiple Context's
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||
static void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{s().m_userMapMutex};
|
||||
const auto it = s().m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (it != s().m_userMap.end()) {
|
||||
@@ -479,14 +474,15 @@ public:
|
||||
s().m_userMap.emplace(std::make_pair(scopep, userKey), userData);
|
||||
}
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||
static void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{s().m_userMapMutex};
|
||||
const auto& it = vlstd::as_const(s().m_userMap).find(std::make_pair(scopep, userKey));
|
||||
if (VL_UNLIKELY(it == s().m_userMap.end())) return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
public: // But only for verilated.cpp
|
||||
// METHODS - But only for verilated.cpp
|
||||
|
||||
// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope on destruction, so we only iterate.
|
||||
@@ -512,8 +508,7 @@ public: // But only for verilated.cpp
|
||||
}
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - hierarchy
|
||||
// METHODS - hierarchy - only for verilated*.cpp
|
||||
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
|
||||
// Slow ok - called at construction for VPI accessible elements
|
||||
const VerilatedLockGuard lock{s().m_hierMapMutex};
|
||||
@@ -534,8 +529,7 @@ public: // But only for verilated*.cpp
|
||||
return &s().m_hierMap;
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - export names
|
||||
// METHODS - export names - only for verilated*.cpp
|
||||
|
||||
// Each function prototype is converted to a function number which we
|
||||
// then use to index a 2D table also indexed by scope number, because we
|
||||
|
||||
@@ -0,0 +1,240 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
// Copyright 2003-2022 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 probability distribution implementation code
|
||||
///
|
||||
/// Verilator always adds this file to the Makefile for the linker.
|
||||
///
|
||||
/// Those macro/function/variable starting or ending in _ are internal,
|
||||
/// however many of the other function/macros here are also internal.
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#include "verilated_config.h"
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
//===========================================================================
|
||||
// Dist
|
||||
|
||||
static double _vl_dbase_uniform(IData& seedr, int32_t start, int32_t end) VL_MT_SAFE {
|
||||
union u_s {
|
||||
float s;
|
||||
unsigned stemp;
|
||||
} u;
|
||||
|
||||
const double d = 0.00000011920928955078125;
|
||||
if (VL_UNLIKELY(seedr == 0)) seedr = 259341593;
|
||||
|
||||
double a;
|
||||
double b;
|
||||
if (VL_UNCOVERABLE(start >= end)) { // With current usage shound't occur
|
||||
a = 0.0; // LCOV_EXCL_LINE
|
||||
b = 2147483647.0; // LCOV_EXCL_LINE
|
||||
} else {
|
||||
a = static_cast<double>(start);
|
||||
b = static_cast<double>(end);
|
||||
}
|
||||
seedr = 69069 * seedr + 1;
|
||||
u.stemp = seedr;
|
||||
u.stemp = (u.stemp >> 9) | 0x3f800000;
|
||||
|
||||
double c = static_cast<double>(u.s);
|
||||
c = c + (c * d);
|
||||
c = ((b - a) * (c - 1.0)) + a;
|
||||
return c;
|
||||
}
|
||||
|
||||
static double _vl_dbase_normal(IData& seedr, int32_t mean, int32_t deviation) VL_MT_SAFE {
|
||||
double v1 = 0.0;
|
||||
double v2 = 0.0;
|
||||
double s = 1.0;
|
||||
while ((s >= 1.0) || (s == 0.0)) {
|
||||
v1 = _vl_dbase_uniform(seedr, -1, 1);
|
||||
v2 = _vl_dbase_uniform(seedr, -1, 1);
|
||||
s = v1 * v1 + v2 * v2;
|
||||
}
|
||||
s = v1 * std::sqrt(-2.0 * log(s) / s);
|
||||
v1 = static_cast<double>(deviation);
|
||||
v2 = static_cast<double>(mean);
|
||||
return (s * v1 + v2);
|
||||
}
|
||||
|
||||
static double _vl_dbase_exponential(IData& seedr, int32_t mean) VL_MT_SAFE {
|
||||
double n = _vl_dbase_uniform(seedr, 0, 1);
|
||||
if (n != 0) n = -log(n) * mean;
|
||||
return n;
|
||||
}
|
||||
|
||||
static double _vl_dbase_chi_square(IData& seedr, int32_t deg_of_free) VL_MT_SAFE {
|
||||
double x;
|
||||
if (deg_of_free % 2) {
|
||||
x = _vl_dbase_normal(seedr, 0, 1);
|
||||
x = x * x;
|
||||
} else {
|
||||
x = 0.0;
|
||||
}
|
||||
for (int32_t k = 2; k <= deg_of_free; k += 2) x = x + 2 * _vl_dbase_exponential(seedr, 1);
|
||||
return x;
|
||||
}
|
||||
|
||||
IData VL_DIST_CHI_SQUARE(IData& seedr, IData udf) VL_MT_SAFE {
|
||||
const int32_t df = static_cast<int32_t>(udf);
|
||||
if (VL_UNLIKELY(df <= 0)) {
|
||||
// Chi_square distribution must have positive degree of freedom
|
||||
return 0;
|
||||
}
|
||||
double r = _vl_dbase_chi_square(seedr, df);
|
||||
int32_t i;
|
||||
if (r >= 0) {
|
||||
i = static_cast<int32_t>(r + 0.5);
|
||||
} else {
|
||||
r = -r; // LCOV_EXCL_LINE
|
||||
i = static_cast<int32_t>(r + 0.5); // LCOV_EXCL_LINE
|
||||
i = -i; // LCOV_EXCL_LINE
|
||||
}
|
||||
return static_cast<IData>(i);
|
||||
}
|
||||
|
||||
IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE {
|
||||
const int32_t k = static_cast<int32_t>(uk);
|
||||
const int32_t mean = static_cast<int32_t>(umean);
|
||||
if (VL_UNLIKELY(k <= 0)) {
|
||||
// k-stage erlangian distribution must have positive k
|
||||
return 0;
|
||||
}
|
||||
double x = 1.0;
|
||||
for (int32_t i = 1; i <= k; i++) { x = x * _vl_dbase_uniform(seedr, 0, 1); }
|
||||
const double a = static_cast<double>(mean);
|
||||
const double b = static_cast<double>(k);
|
||||
double r = -a * log(x) / b;
|
||||
int32_t i;
|
||||
if (r >= 0) {
|
||||
i = static_cast<int32_t>(r + 0.5);
|
||||
} else {
|
||||
r = -r;
|
||||
i = static_cast<int32_t>(r + 0.5);
|
||||
i = -i;
|
||||
}
|
||||
return static_cast<IData>(i);
|
||||
}
|
||||
|
||||
IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE {
|
||||
const int32_t mean = static_cast<int32_t>(umean);
|
||||
if (VL_UNLIKELY(mean <= 0)) {
|
||||
// Exponential distribution must have a positive mean
|
||||
return 0;
|
||||
}
|
||||
int32_t i;
|
||||
double r = _vl_dbase_exponential(seedr, mean);
|
||||
if (r >= 0) {
|
||||
i = static_cast<int32_t>(r + 0.5);
|
||||
} else {
|
||||
r = -r; // LCOV_EXCL_LINE
|
||||
i = static_cast<int32_t>(r + 0.5); // LCOV_EXCL_LINE
|
||||
i = -i; // LCOV_EXCL_LINE
|
||||
}
|
||||
return static_cast<IData>(i);
|
||||
}
|
||||
|
||||
IData VL_DIST_NORMAL(IData& seedr, IData umean, IData usd) VL_MT_SAFE {
|
||||
const int32_t mean = static_cast<int32_t>(umean);
|
||||
const int32_t sd = static_cast<int32_t>(usd);
|
||||
double r = _vl_dbase_normal(seedr, mean, sd);
|
||||
int32_t i;
|
||||
if (r >= 0) {
|
||||
i = static_cast<int32_t>(r + 0.5);
|
||||
} else {
|
||||
r = -r;
|
||||
i = static_cast<int32_t>(r + 0.5);
|
||||
i = -i;
|
||||
}
|
||||
return static_cast<IData>(i);
|
||||
}
|
||||
|
||||
IData VL_DIST_POISSON(IData& seedr, IData umean) VL_MT_SAFE {
|
||||
const int32_t mean = static_cast<int32_t>(umean);
|
||||
if (VL_UNLIKELY(mean <= 0)) {
|
||||
// Poisson distribution must have a positive mean
|
||||
return 0;
|
||||
}
|
||||
int32_t i = 0;
|
||||
double q = -static_cast<double>(mean);
|
||||
double p = exp(q);
|
||||
q = _vl_dbase_uniform(seedr, 0, 1);
|
||||
while (p < q) {
|
||||
++i;
|
||||
q = _vl_dbase_uniform(seedr, 0, 1) * q;
|
||||
}
|
||||
return static_cast<IData>(i);
|
||||
}
|
||||
|
||||
IData VL_DIST_T(IData& seedr, IData udf) VL_MT_SAFE {
|
||||
const int32_t df = static_cast<int32_t>(udf);
|
||||
if (VL_UNLIKELY(df <= 0)) {
|
||||
// t distribution must have positive degree of freedom
|
||||
return 0;
|
||||
}
|
||||
const double chi2 = _vl_dbase_chi_square(seedr, df);
|
||||
const double div = chi2 / static_cast<double>(df);
|
||||
const double root = std::sqrt(div);
|
||||
double r = _vl_dbase_normal(seedr, 0, 1) / root;
|
||||
int32_t i;
|
||||
if (r >= 0) {
|
||||
i = static_cast<int32_t>(r + 0.5);
|
||||
} else {
|
||||
r = -r;
|
||||
i = static_cast<int32_t>(r + 0.5);
|
||||
i = -i;
|
||||
}
|
||||
return static_cast<IData>(i);
|
||||
}
|
||||
|
||||
IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE {
|
||||
int32_t start = static_cast<int32_t>(ustart);
|
||||
int32_t end = static_cast<int32_t>(uend);
|
||||
if (VL_UNLIKELY(start >= end)) return start;
|
||||
int32_t i;
|
||||
if (end != std::numeric_limits<int32_t>::max()) {
|
||||
++end;
|
||||
const double r = _vl_dbase_uniform(seedr, start, end);
|
||||
if (r >= 0) {
|
||||
i = static_cast<int32_t>(r);
|
||||
} else {
|
||||
i = static_cast<int32_t>(r - 1);
|
||||
}
|
||||
if (i < start) i = start;
|
||||
if (i >= end) i = end - 1;
|
||||
} else if (start != std::numeric_limits<int32_t>::min()) {
|
||||
--start;
|
||||
const double r = _vl_dbase_uniform(seedr, start, end) + 1.0;
|
||||
if (r >= 0) {
|
||||
i = static_cast<int32_t>(r);
|
||||
} else {
|
||||
i = static_cast<int32_t>(r - 1); // LCOV_EXCL_LINE
|
||||
}
|
||||
if (i <= start) i = start + 1;
|
||||
if (i > end) i = end;
|
||||
} else {
|
||||
double r = (_vl_dbase_uniform(seedr, start, end) + 2147483648.0) / 4294967295.0;
|
||||
r = r * 4294967296.0 - 2147483648.0;
|
||||
if (r >= 0) {
|
||||
i = static_cast<int32_t>(r);
|
||||
} else {
|
||||
i = static_cast<int32_t>(r - 1);
|
||||
}
|
||||
}
|
||||
return static_cast<IData>(i);
|
||||
}
|
||||
@@ -17,11 +17,10 @@
|
||||
//=============================================================================
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated_profiler.h"
|
||||
|
||||
#if VL_THREADED
|
||||
#include "verilated_threads.h"
|
||||
#endif
|
||||
|
||||
#include <fstream>
|
||||
#include <string>
|
||||
@@ -31,7 +30,7 @@
|
||||
|
||||
// Internal note: Globals may multi-construct, see verilated.cpp top.
|
||||
|
||||
VL_THREAD_LOCAL VlExecutionProfiler::ExecutionTrace VlExecutionProfiler::t_trace;
|
||||
thread_local VlExecutionProfiler::ExecutionTrace VlExecutionProfiler::t_trace;
|
||||
|
||||
constexpr const char* const VlExecutionRecord::s_ascii[];
|
||||
|
||||
@@ -60,54 +59,85 @@ uint16_t VlExecutionRecord::getcpu() {
|
||||
//=============================================================================
|
||||
// VlExecutionProfiler implementation
|
||||
|
||||
template <size_t N> static size_t roundUptoMultipleOf(size_t value) {
|
||||
template <size_t N>
|
||||
static size_t roundUptoMultipleOf(size_t value) {
|
||||
static_assert((N & (N - 1)) == 0, "'N' must be a power of 2");
|
||||
size_t mask = N - 1;
|
||||
return (value + mask) & ~mask;
|
||||
}
|
||||
|
||||
VlExecutionProfiler::VlExecutionProfiler() {
|
||||
VlExecutionProfiler::VlExecutionProfiler(VerilatedContext& context)
|
||||
: m_context{context} {
|
||||
// Setup profiling on main thread
|
||||
setupThread(0);
|
||||
}
|
||||
|
||||
void VlExecutionProfiler::configure(const VerilatedContext& context) {
|
||||
void VlExecutionProfiler::configure() {
|
||||
|
||||
if (VL_UNLIKELY(m_enabled)) {
|
||||
--m_windowCount;
|
||||
if (VL_UNLIKELY(m_windowCount == context.profExecWindow())) {
|
||||
if (VL_UNLIKELY(m_windowCount == m_context.profExecWindow())) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("+ profile start collection\n"););
|
||||
clear(); // Clear the profile after the cache warm-up cycles.
|
||||
m_tickBegin = VL_CPU_TICK();
|
||||
} else if (VL_UNLIKELY(m_windowCount == 0)) {
|
||||
const uint64_t tickEnd = VL_CPU_TICK();
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("+ profile end\n"););
|
||||
const std::string& fileName = context.profExecFilename();
|
||||
const std::string& fileName = m_context.profExecFilename();
|
||||
dump(fileName.c_str(), tickEnd);
|
||||
m_enabled = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const uint64_t startReq = context.profExecStart() + 1; // + 1, so we can start at time 0
|
||||
const uint64_t startReq = m_context.profExecStart() + 1; // + 1, so we can start at time 0
|
||||
|
||||
if (VL_UNLIKELY(m_lastStartReq < startReq && VL_TIME_Q() >= context.profExecStart())) {
|
||||
if (VL_UNLIKELY(m_lastStartReq < startReq && VL_TIME_Q() >= m_context.profExecStart())) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("+ profile start warmup\n"););
|
||||
VL_DEBUG_IF(assert(m_windowCount == 0););
|
||||
m_enabled = true;
|
||||
m_windowCount = context.profExecWindow() * 2;
|
||||
m_windowCount = m_context.profExecWindow() * 2;
|
||||
m_lastStartReq = startReq;
|
||||
}
|
||||
}
|
||||
|
||||
VerilatedVirtualBase* VlExecutionProfiler::construct(VerilatedContext& context) {
|
||||
VlExecutionProfiler* const selfp = new VlExecutionProfiler{context};
|
||||
if (VlThreadPool* const threadPoolp = static_cast<VlThreadPool*>(context.threadPoolp())) {
|
||||
for (int i = 0; i < threadPoolp->numThreads(); ++i) {
|
||||
// Data to pass to worker thread initialization
|
||||
struct Data {
|
||||
VlExecutionProfiler* const selfp;
|
||||
const uint32_t threadId;
|
||||
} data{selfp, static_cast<uint32_t>(i + 1)};
|
||||
|
||||
// Initialize worker thread
|
||||
threadPoolp->workerp(i)->addTask(
|
||||
[](void* userp, bool) {
|
||||
Data* const datap = static_cast<Data*>(userp);
|
||||
datap->selfp->setupThread(datap->threadId);
|
||||
},
|
||||
&data);
|
||||
|
||||
// Wait until initialization is complete
|
||||
threadPoolp->workerp(i)->wait();
|
||||
}
|
||||
}
|
||||
return selfp;
|
||||
}
|
||||
|
||||
void VlExecutionProfiler::setupThread(uint32_t threadId) {
|
||||
// Reserve some space in the thread-local profiling buffer, in order to try to avoid malloc
|
||||
// while profiling.
|
||||
t_trace.reserve(RESERVED_TRACE_CAPACITY);
|
||||
// Register thread-local buffer in list of all buffers
|
||||
bool exists;
|
||||
{
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
bool exists = !m_traceps.emplace(threadId, &t_trace).second;
|
||||
assert(!exists);
|
||||
exists = !m_traceps.emplace(threadId, &t_trace).second;
|
||||
}
|
||||
if (VL_UNLIKELY(exists)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "multiple initialization of profiler on some thread");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,14 +168,12 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
|
||||
Verilated::threadContextp()->profExecWindow());
|
||||
const unsigned threads = static_cast<unsigned>(m_traceps.size());
|
||||
fprintf(fp, "VLPROF stat threads %u\n", threads);
|
||||
#ifdef VL_THREADED
|
||||
fprintf(fp, "VLPROF stat yields %" PRIu64 "\n", VlMTaskVertex::yields());
|
||||
#endif
|
||||
|
||||
// Copy /proc/cpuinfo into this output so verilator_gantt can be run on
|
||||
// a different machine
|
||||
{
|
||||
const std::unique_ptr<std::ifstream> ifp{new std::ifstream("/proc/cpuinfo")};
|
||||
const std::unique_ptr<std::ifstream> ifp{new std::ifstream{"/proc/cpuinfo"}};
|
||||
if (!ifp->fail()) {
|
||||
std::string line;
|
||||
while (std::getline(*ifp, line)) { fprintf(fp, "VLPROFPROC %s\n", line.c_str()); }
|
||||
|
||||
@@ -24,10 +24,6 @@
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#ifndef VL_PROFILER
|
||||
#error "verilated_profiler.h/cpp expects VL_PROFILER (from --prof-{exec, pgo}"
|
||||
#endif
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <array>
|
||||
@@ -38,18 +34,18 @@
|
||||
#include <vector>
|
||||
|
||||
class VlExecutionProfiler;
|
||||
class VlThreadPool;
|
||||
|
||||
//=============================================================================
|
||||
// Macros to simplify generated code
|
||||
|
||||
#define VL_EXEC_TRACE_ADD_RECORD(vlSymsp) \
|
||||
if (VL_UNLIKELY((vlSymsp)->__Vm_executionProfiler.enabled())) \
|
||||
(vlSymsp)->__Vm_executionProfiler.addRecord()
|
||||
if (VL_UNLIKELY((vlSymsp)->__Vm_executionProfilerp->enabled())) \
|
||||
(vlSymsp)->__Vm_executionProfilerp->addRecord()
|
||||
|
||||
//=============================================================================
|
||||
// Return high-precision counter for profiling, or 0x0 if not available
|
||||
VL_ATTR_ALWINLINE
|
||||
inline QData VL_CPU_TICK() {
|
||||
VL_ATTR_ALWINLINE QData VL_CPU_TICK() {
|
||||
uint64_t val;
|
||||
VL_GET_CPU_TICK(val);
|
||||
return val;
|
||||
@@ -136,7 +132,7 @@ static_assert(std::is_trivially_destructible<VlExecutionRecord>::value,
|
||||
//=============================================================================
|
||||
// VlExecutionProfiler is for collecting profiling data about model execution
|
||||
|
||||
class VlExecutionProfiler final {
|
||||
class VlExecutionProfiler final : public VerilatedVirtualBase {
|
||||
// CONSTANTS
|
||||
|
||||
// In order to try to avoid dynamic memory allocations during the actual profiling phase,
|
||||
@@ -154,7 +150,8 @@ class VlExecutionProfiler final {
|
||||
using ExecutionTrace = std::vector<VlExecutionRecord>;
|
||||
|
||||
// STATE
|
||||
static VL_THREAD_LOCAL ExecutionTrace t_trace; // thread-local trace buffers
|
||||
VerilatedContext& m_context; // The context this profiler is under
|
||||
static thread_local ExecutionTrace t_trace; // thread-local trace buffers
|
||||
mutable VerilatedMutex m_mutex;
|
||||
// Map from thread id to &t_trace of given thread
|
||||
std::map<uint32_t, ExecutionTrace*> m_traceps VL_GUARDED_BY(m_mutex);
|
||||
@@ -167,31 +164,36 @@ class VlExecutionProfiler final {
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
VlExecutionProfiler();
|
||||
explicit VlExecutionProfiler(VerilatedContext& context);
|
||||
~VlExecutionProfiler() override = default;
|
||||
|
||||
// METHODS
|
||||
|
||||
// Is profiling enabled
|
||||
inline bool enabled() const { return m_enabled; }
|
||||
bool enabled() const { return m_enabled; }
|
||||
// Append a trace record to the trace buffer of the current thread
|
||||
inline VlExecutionRecord& addRecord() {
|
||||
static VlExecutionRecord& addRecord() {
|
||||
t_trace.emplace_back();
|
||||
return t_trace.back();
|
||||
}
|
||||
// Configure profiler (called in beginning of 'eval')
|
||||
void configure(const VerilatedContext&);
|
||||
void configure();
|
||||
// Setup profiling on a particular thread;
|
||||
void setupThread(uint32_t threadId);
|
||||
// Clear all profiling data
|
||||
void clear() VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
// Write profiling data into file
|
||||
void dump(const char* filenamep, uint64_t tickEnd) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
|
||||
// Passed to VerilatedContext to create the VlExecutionProfiler profiler instance
|
||||
static VerilatedVirtualBase* construct(VerilatedContext& context);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlPgoProfiler is for collecting profiling data for PGO
|
||||
|
||||
template <std::size_t T_Entries> class VlPgoProfiler final {
|
||||
template <std::size_t T_Entries>
|
||||
class VlPgoProfiler final {
|
||||
// TYPES
|
||||
struct Record final {
|
||||
const std::string m_name; // Hashed name of mtask/etc
|
||||
|
||||
@@ -24,8 +24,10 @@
|
||||
#define VERILATOR_VERILATED_SAVE_CPP_
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
|
||||
#include "verilated_save.h"
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_imp.h"
|
||||
|
||||
#include <cerrno>
|
||||
@@ -38,13 +40,13 @@
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef O_LARGEFILE // For example on WIN32
|
||||
#ifndef O_LARGEFILE // WIN32 headers omit this
|
||||
# define O_LARGEFILE 0
|
||||
#endif
|
||||
#ifndef O_NONBLOCK
|
||||
#ifndef O_NONBLOCK // WIN32 headers omit this
|
||||
# define O_NONBLOCK 0
|
||||
#endif
|
||||
#ifndef O_CLOEXEC
|
||||
#ifndef O_CLOEXEC // WIN32 headers omit this
|
||||
# define O_CLOEXEC 0
|
||||
#endif
|
||||
// clang-format on
|
||||
@@ -170,18 +172,18 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
header();
|
||||
}
|
||||
|
||||
void VerilatedSave::close() VL_MT_UNSAFE_ONE {
|
||||
void VerilatedSave::closeImp() VL_MT_UNSAFE_ONE {
|
||||
if (!isOpen()) return;
|
||||
trailer();
|
||||
flush();
|
||||
flushImp();
|
||||
m_isOpen = false;
|
||||
::close(m_fd); // May get error, just ignore it
|
||||
}
|
||||
|
||||
void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
|
||||
void VerilatedRestore::closeImp() VL_MT_UNSAFE_ONE {
|
||||
if (!isOpen()) return;
|
||||
trailer();
|
||||
flush();
|
||||
flushImp();
|
||||
m_isOpen = false;
|
||||
::close(m_fd); // May get error, just ignore it
|
||||
}
|
||||
@@ -189,7 +191,7 @@ void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
|
||||
//=============================================================================
|
||||
// Buffer management
|
||||
|
||||
void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
|
||||
void VerilatedSave::flushImp() VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
const uint8_t* wp = m_bufp;
|
||||
|
||||
+20
-12
@@ -23,6 +23,7 @@
|
||||
#define VERILATOR_VERILATED_SAVE_C_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <string>
|
||||
@@ -61,9 +62,9 @@ public:
|
||||
m_bufp = new uint8_t[bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
}
|
||||
/// Flish, close, and destruct
|
||||
/// Flush, close, and destruct
|
||||
virtual ~VerilatedSerialize() {
|
||||
close();
|
||||
// Child classes will need to typically call closeImp() in destructors
|
||||
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
|
||||
}
|
||||
// METHODS
|
||||
@@ -77,7 +78,7 @@ public:
|
||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||
/// Write data to stream
|
||||
VerilatedSerialize& write(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
const uint8_t* __restrict dp = (const uint8_t* __restrict)datap;
|
||||
const uint8_t* __restrict dp = static_cast<const uint8_t* __restrict>(datap);
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size;
|
||||
@@ -136,7 +137,7 @@ public:
|
||||
}
|
||||
/// Destruct
|
||||
virtual ~VerilatedDeserialize() {
|
||||
close();
|
||||
// Child classes will need to typically call closeImp() in destructors
|
||||
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
|
||||
}
|
||||
// METHODS
|
||||
@@ -189,21 +190,24 @@ class VerilatedSave final : public VerilatedSerialize {
|
||||
private:
|
||||
int m_fd = -1; // File descriptor we're writing to
|
||||
|
||||
void closeImp() VL_MT_UNSAFE_ONE;
|
||||
void flushImp() VL_MT_UNSAFE_ONE;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
/// Construct new object
|
||||
VerilatedSave() = default;
|
||||
/// Flush, close and destruct
|
||||
virtual ~VerilatedSave() override { close(); }
|
||||
~VerilatedSave() override { closeImp(); }
|
||||
// METHODS
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
/// Flush and close the file
|
||||
virtual void close() override VL_MT_UNSAFE_ONE;
|
||||
void close() override VL_MT_UNSAFE_ONE { closeImp(); }
|
||||
/// Flush data to file
|
||||
virtual void flush() override VL_MT_UNSAFE_ONE;
|
||||
void flush() override VL_MT_UNSAFE_ONE { flushImp(); }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -216,12 +220,15 @@ class VerilatedRestore final : public VerilatedDeserialize {
|
||||
private:
|
||||
int m_fd = -1; // File descriptor we're writing to
|
||||
|
||||
void closeImp() VL_MT_UNSAFE_ONE;
|
||||
void flushImp() VL_MT_UNSAFE_ONE {}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
/// Construct new object
|
||||
VerilatedRestore() = default;
|
||||
/// Flush, close and destruct
|
||||
virtual ~VerilatedRestore() override { close(); }
|
||||
~VerilatedRestore() override { closeImp(); }
|
||||
|
||||
// METHODS
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
@@ -229,9 +236,9 @@ public:
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
/// Close the file
|
||||
virtual void close() override VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() override VL_MT_UNSAFE_ONE {}
|
||||
virtual void fill() override VL_MT_UNSAFE_ONE;
|
||||
void close() override VL_MT_UNSAFE_ONE { closeImp(); }
|
||||
void flush() override VL_MT_UNSAFE_ONE { flushImp(); }
|
||||
void fill() override VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -287,7 +294,8 @@ inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, std::string& r
|
||||
uint32_t len = 0;
|
||||
os >> len;
|
||||
rhs.resize(len);
|
||||
return os.read((void*)rhs.data(), len);
|
||||
// C cast is required below
|
||||
return os.read((void*)(rhs.data()), len);
|
||||
}
|
||||
VerilatedSerialize& operator<<(VerilatedSerialize& os, VerilatedContext* rhsp);
|
||||
VerilatedDeserialize& operator>>(VerilatedDeserialize& os, VerilatedContext* rhsp);
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
// DESCRIPTION: Verilator: built-in packages and classes
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2022 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 IEEE std:: header
|
||||
///
|
||||
/// This file is included automatically by Verilator when a std::mailbox or
|
||||
/// std::semaphore is referenced.
|
||||
///
|
||||
/// This file is not part of the Verilated public-facing API.
|
||||
/// It is only for internal use.
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
// verilator lint_off DECLFILENAME
|
||||
// verilator lint_off TIMESCALEMOD
|
||||
// verilator lint_off UNUSEDSIGNAL
|
||||
package std;
|
||||
class mailbox #(type T);
|
||||
protected int m_bound;
|
||||
protected T m_queue[$];
|
||||
|
||||
function new(int bound = 0);
|
||||
m_bound = bound;
|
||||
endfunction
|
||||
|
||||
function int num();
|
||||
return m_queue.size();
|
||||
endfunction
|
||||
|
||||
task put(T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
if (m_bound != 0)
|
||||
wait (m_queue.size() < m_bound);
|
||||
m_queue.push_back(message);
|
||||
`endif
|
||||
endtask
|
||||
|
||||
function int try_put(T message);
|
||||
if (num() < m_bound) begin
|
||||
m_queue.push_back(message);
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
|
||||
task get(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
message = m_queue.pop_front();
|
||||
`endif
|
||||
endtask
|
||||
|
||||
function int try_get(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue.pop_front();
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
|
||||
task peek(ref T message);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_queue.size() > 0);
|
||||
message = m_queue[0];
|
||||
`endif
|
||||
endtask
|
||||
|
||||
function int try_peek(ref T message);
|
||||
if (num() > 0) begin
|
||||
message = m_queue[0];
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
|
||||
class semaphore;
|
||||
protected int m_keyCount;
|
||||
|
||||
function new(int keyCount = 0);
|
||||
m_keyCount = keyCount;
|
||||
endfunction
|
||||
|
||||
function void put(int keyCount = 1);
|
||||
m_keyCount += keyCount;
|
||||
endfunction
|
||||
|
||||
task get(int keyCount = 1);
|
||||
`ifdef VERILATOR_TIMING
|
||||
wait (m_keyCount >= keyCount);
|
||||
m_keyCount -= keyCount;
|
||||
`endif
|
||||
endtask
|
||||
|
||||
function int try_get(int keyCount = 1);
|
||||
if (m_keyCount >= keyCount) begin
|
||||
m_keyCount -= keyCount;
|
||||
return 1;
|
||||
end
|
||||
return 0;
|
||||
endfunction
|
||||
endclass
|
||||
endpackage
|
||||
|
||||
// verilator lint_off IMPORTSTAR
|
||||
import std::*;
|
||||
@@ -53,14 +53,14 @@ public:
|
||||
: m_left{left}
|
||||
, m_right{right} {}
|
||||
~VerilatedRange() = default;
|
||||
int left() const { return m_left; }
|
||||
int right() const { return m_right; }
|
||||
int low() const { return (m_left < m_right) ? m_left : m_right; }
|
||||
int high() const { return (m_left > m_right) ? m_left : m_right; }
|
||||
int elements() const {
|
||||
int left() const VL_PURE { return m_left; }
|
||||
int right() const VL_PURE { return m_right; }
|
||||
int low() const VL_PURE { return (m_left < m_right) ? m_left : m_right; }
|
||||
int high() const VL_PURE { return (m_left > m_right) ? m_left : m_right; }
|
||||
int elements() const VL_PURE {
|
||||
return (VL_LIKELY(m_left >= m_right) ? (m_left - m_right + 1) : (m_right - m_left + 1));
|
||||
}
|
||||
int increment() const { return (m_left >= m_right) ? 1 : -1; }
|
||||
int increment() const VL_PURE { return (m_left >= m_right) ? 1 : -1; }
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
@@ -134,7 +134,6 @@ public:
|
||||
initUnpacked(ulims);
|
||||
}
|
||||
|
||||
public:
|
||||
~VerilatedVarProps() = default;
|
||||
// METHODS
|
||||
bool magicOk() const { return m_magic == MAGIC; }
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#define VERILATOR_VERILATED_SYMS_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_sym_props.h"
|
||||
|
||||
|
||||
@@ -22,11 +22,8 @@
|
||||
//=============================================================================
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated_threads.h"
|
||||
|
||||
#ifdef VL_PROFILER
|
||||
#include "verilated_profiler.h"
|
||||
#endif
|
||||
#include "verilated_threads.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
@@ -51,68 +48,59 @@ VlMTaskVertex::VlMTaskVertex(uint32_t upstreamDepCount)
|
||||
//=============================================================================
|
||||
// VlWorkerThread
|
||||
|
||||
VlWorkerThread::VlWorkerThread(uint32_t threadId, VerilatedContext* contextp,
|
||||
VlExecutionProfiler* profilerp)
|
||||
VlWorkerThread::VlWorkerThread(VerilatedContext* contextp)
|
||||
: m_ready_size{0}
|
||||
, m_exiting{false}
|
||||
, m_cthread{startWorker, this, threadId, profilerp}
|
||||
, m_contextp{contextp} {}
|
||||
, m_cthread{startWorker, this, contextp} {}
|
||||
|
||||
VlWorkerThread::~VlWorkerThread() {
|
||||
m_exiting.store(true, std::memory_order_release);
|
||||
wakeUp();
|
||||
shutdown();
|
||||
// The thread should exit; join it.
|
||||
m_cthread.join();
|
||||
}
|
||||
|
||||
static void shutdownTask(void*, bool) { // LCOV_EXCL_LINE
|
||||
// Deliberately empty, we use the address of this function as a magic number
|
||||
}
|
||||
|
||||
void VlWorkerThread::shutdown() { addTask(shutdownTask, nullptr); }
|
||||
|
||||
void VlWorkerThread::wait() {
|
||||
// Enqueue a task that sets this flag. Execution is in-order so this ensures completion.
|
||||
std::atomic<bool> flag{false};
|
||||
addTask([](void* flagp, bool) { static_cast<std::atomic<bool>*>(flagp)->store(true); }, &flag);
|
||||
// Spin wait
|
||||
for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||
if (flag.load()) return;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
// Yield wait
|
||||
while (!flag.load()) std::this_thread::yield();
|
||||
}
|
||||
|
||||
void VlWorkerThread::workerLoop() {
|
||||
ExecRec work;
|
||||
work.m_fnp = nullptr;
|
||||
|
||||
// Wait for the first task without spinning, in case the thread is never actually used.
|
||||
dequeWork</* SpinWait: */ false>(&work);
|
||||
|
||||
while (true) {
|
||||
if (VL_LIKELY(!work.m_fnp)) dequeWork(&work);
|
||||
|
||||
// Do this here, not above, to avoid a race with the destructor.
|
||||
if (VL_UNLIKELY(m_exiting.load(std::memory_order_acquire))) break;
|
||||
|
||||
if (VL_LIKELY(work.m_fnp)) {
|
||||
work.m_fnp(work.m_selfp, work.m_evenCycle);
|
||||
work.m_fnp = nullptr;
|
||||
}
|
||||
if (VL_UNLIKELY(work.m_fnp == shutdownTask)) break;
|
||||
work.m_fnp(work.m_selfp, work.m_evenCycle);
|
||||
// Wait for next task with spinning.
|
||||
dequeWork</* SpinWait: */ true>(&work);
|
||||
}
|
||||
}
|
||||
|
||||
void VlWorkerThread::startWorker(VlWorkerThread* workerp, uint32_t threadId,
|
||||
VlExecutionProfiler* profilerp) {
|
||||
Verilated::threadContextp(workerp->m_contextp);
|
||||
#ifdef VL_PROFILER
|
||||
// Note: setupThread is not defined without VL_PROFILER, hence the #ifdef. Still, we might
|
||||
// not be profiling execution (e.g.: PGO only), so profilerp might still be nullptr.
|
||||
if (profilerp) profilerp->setupThread(threadId);
|
||||
#endif
|
||||
void VlWorkerThread::startWorker(VlWorkerThread* workerp, VerilatedContext* contextp) {
|
||||
Verilated::threadContextp(contextp);
|
||||
workerp->workerLoop();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VlThreadPool
|
||||
|
||||
VlThreadPool::VlThreadPool(VerilatedContext* contextp, int nThreads,
|
||||
VlExecutionProfiler* profiler) {
|
||||
// --threads N passes nThreads=N-1, as the "main" threads counts as 1
|
||||
++nThreads;
|
||||
const unsigned cpus = std::thread::hardware_concurrency();
|
||||
if (cpus < nThreads) {
|
||||
static int warnedOnce = 0;
|
||||
if (!warnedOnce++) {
|
||||
VL_PRINTF_MT("%%Warning: System has %u CPUs but model Verilated with"
|
||||
" --threads %d; may run slow.\n",
|
||||
cpus, nThreads);
|
||||
}
|
||||
}
|
||||
// Create worker threads
|
||||
for (uint32_t threadId = 1; threadId < nThreads; ++threadId) {
|
||||
m_workers.push_back(new VlWorkerThread{threadId, contextp, profiler});
|
||||
}
|
||||
VlThreadPool::VlThreadPool(VerilatedContext* contextp, unsigned nThreads) {
|
||||
for (unsigned i = 0; i < nThreads; ++i) m_workers.push_back(new VlWorkerThread{contextp});
|
||||
}
|
||||
|
||||
VlThreadPool::~VlThreadPool() {
|
||||
|
||||
+30
-41
@@ -24,16 +24,8 @@
|
||||
#define VERILATOR_VERILATED_THREADS_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h" // for VerilatedMutex and clang annotations
|
||||
|
||||
#ifndef VL_THREADED
|
||||
// Hitting this likely means verilated_threads.cpp is being compiled when
|
||||
// 'verilator --threads' was not used. 'verilator --threads' sets
|
||||
// VL_THREADED.
|
||||
// Alternatively it is always safe but may harm performance to always
|
||||
// define VL_THREADED for all compiles.
|
||||
#error "verilated_threads.h/cpp expected VL_THREADED (from verilator --threads)"
|
||||
#endif
|
||||
#include "verilated.h" // for VerilatedMutex and clang annotations
|
||||
|
||||
#include <atomic>
|
||||
#include <condition_variable>
|
||||
@@ -50,6 +42,9 @@
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
class VlExecutionProfiler;
|
||||
class VlThreadPool;
|
||||
|
||||
// VlMTaskVertex and VlThreadpool will work with multiple model class types.
|
||||
// Since the type is opaque to VlMTaskVertex and VlThreadPool, represent it
|
||||
// as a void* here.
|
||||
@@ -99,7 +94,7 @@ public:
|
||||
// Upstream mtasks must call this when they complete.
|
||||
// Returns true when the current MTaskVertex becomes ready to execute,
|
||||
// false while it's still waiting on more dependencies.
|
||||
inline bool signalUpstreamDone(bool evenCycle) {
|
||||
bool signalUpstreamDone(bool evenCycle) {
|
||||
if (evenCycle) {
|
||||
const uint32_t upstreamDepsDone
|
||||
= 1 + m_upstreamDepsDone.fetch_add(1, std::memory_order_release);
|
||||
@@ -112,11 +107,11 @@ public:
|
||||
return (upstreamDepsDone_prev == 1);
|
||||
}
|
||||
}
|
||||
inline bool areUpstreamDepsDone(bool evenCycle) const {
|
||||
bool areUpstreamDepsDone(bool evenCycle) const {
|
||||
const uint32_t target = evenCycle ? m_upstreamDepCount : 0;
|
||||
return m_upstreamDepsDone.load(std::memory_order_acquire) == target;
|
||||
}
|
||||
inline void waitUntilUpstreamDone(bool evenCycle) const {
|
||||
void waitUntilUpstreamDone(bool evenCycle) const {
|
||||
unsigned ct = 0;
|
||||
while (VL_UNLIKELY(!areUpstreamDepsDone(evenCycle))) {
|
||||
VL_CPU_RELAX();
|
||||
@@ -129,20 +124,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
class VlExecutionProfiler;
|
||||
class VlThreadPool;
|
||||
|
||||
class VlWorkerThread final {
|
||||
private:
|
||||
// TYPES
|
||||
struct ExecRec {
|
||||
VlExecFnp m_fnp; // Function to execute
|
||||
VlSelfP m_selfp; // Symbol table to execute
|
||||
bool m_evenCycle; // Even/odd for flag alternation
|
||||
ExecRec()
|
||||
: m_fnp{nullptr}
|
||||
, m_selfp{nullptr}
|
||||
, m_evenCycle{false} {}
|
||||
VlExecFnp m_fnp = nullptr; // Function to execute
|
||||
VlSelfP m_selfp = nullptr; // Symbol table to execute
|
||||
bool m_evenCycle = false; // Even/odd for flag alternation
|
||||
ExecRec() = default;
|
||||
ExecRec(VlExecFnp fnp, VlSelfP selfp, bool evenCycle)
|
||||
: m_fnp{fnp}
|
||||
, m_selfp{selfp}
|
||||
@@ -162,26 +151,24 @@ private:
|
||||
// Store the size atomically, so we can spin wait
|
||||
std::atomic<size_t> m_ready_size;
|
||||
|
||||
std::atomic<bool> m_exiting; // Worker thread should exit
|
||||
std::thread m_cthread; // Underlying C++ thread record
|
||||
VerilatedContext* const m_contextp; // Context for spawned thread
|
||||
|
||||
VL_UNCOPYABLE(VlWorkerThread);
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit VlWorkerThread(uint32_t threadId, VerilatedContext* contextp,
|
||||
VlExecutionProfiler* profilerp);
|
||||
explicit VlWorkerThread(VerilatedContext* contextp);
|
||||
~VlWorkerThread();
|
||||
|
||||
// METHODS
|
||||
inline void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
template <bool SpinWait>
|
||||
void dequeWork(ExecRec* workp) VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
// Spin for a while, waiting for new data
|
||||
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { //
|
||||
break;
|
||||
if VL_CONSTEXPR_CXX17 (SpinWait) {
|
||||
for (unsigned i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) break;
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
VL_CPU_RELAX();
|
||||
}
|
||||
VerilatedLockGuard lock{m_mutex};
|
||||
while (m_ready.empty()) {
|
||||
@@ -195,8 +182,7 @@ public:
|
||||
m_ready.erase(m_ready.begin());
|
||||
m_ready_size.fetch_sub(1, std::memory_order_relaxed);
|
||||
}
|
||||
inline void wakeUp() { addTask(nullptr, nullptr, false); }
|
||||
inline void addTask(VlExecFnp fnp, VlSelfP selfp, bool evenCycle)
|
||||
void addTask(VlExecFnp fnp, VlSelfP selfp, bool evenCycle = false)
|
||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
bool notify;
|
||||
{
|
||||
@@ -207,12 +193,15 @@ public:
|
||||
}
|
||||
if (notify) m_cv.notify_one();
|
||||
}
|
||||
|
||||
void shutdown(); // Finish current tasks, then terminate thread
|
||||
void wait(); // Blocks calling thread until all tasks complete in this thread
|
||||
|
||||
void workerLoop();
|
||||
static void startWorker(VlWorkerThread* workerp, uint32_t threadId,
|
||||
VlExecutionProfiler* profilerp);
|
||||
static void startWorker(VlWorkerThread* workerp, VerilatedContext* contextp);
|
||||
};
|
||||
|
||||
class VlThreadPool final {
|
||||
class VlThreadPool final : public VerilatedVirtualBase {
|
||||
// MEMBERS
|
||||
std::vector<VlWorkerThread*> m_workers; // our workers
|
||||
|
||||
@@ -221,14 +210,14 @@ public:
|
||||
// Construct a thread pool with 'nThreads' dedicated threads. The thread
|
||||
// pool will create these threads and make them available to execute tasks
|
||||
// via this->workerp(index)->addTask(...)
|
||||
VlThreadPool(VerilatedContext* contextp, int nThreads, VlExecutionProfiler* profilerp);
|
||||
~VlThreadPool();
|
||||
VlThreadPool(VerilatedContext* contextp, unsigned nThreads);
|
||||
~VlThreadPool() override;
|
||||
|
||||
// METHODS
|
||||
inline int numThreads() const { return m_workers.size(); }
|
||||
inline VlWorkerThread* workerp(int index) {
|
||||
int numThreads() const { return m_workers.size(); }
|
||||
VlWorkerThread* workerp(int index) {
|
||||
assert(index >= 0);
|
||||
assert(index < m_workers.size());
|
||||
assert(static_cast<size_t>(index) < m_workers.size());
|
||||
return m_workers[index];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,223 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
// Copyright 2022 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 timing implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all Verilated objects
|
||||
/// that use timing features.
|
||||
///
|
||||
/// See the internals documentation docs/internals.rst for details.
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#include "verilated_timing.h"
|
||||
|
||||
//======================================================================
|
||||
// VlCoroutineHandle:: Methods
|
||||
|
||||
void VlCoroutineHandle::resume() {
|
||||
// Only null if we have a fork..join_any and one of the other child processes resumed the
|
||||
// main process
|
||||
if (VL_LIKELY(m_coro)) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF(" Resuming: "); dump(););
|
||||
m_coro();
|
||||
m_coro = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
void VlCoroutineHandle::dump() const {
|
||||
VL_PRINTF("Process waiting at %s:%d\n", m_fileline.filename(), m_fileline.lineno());
|
||||
}
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// VlDelayScheduler:: Methods
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
void VlDelayScheduler::VlDelayedCoroutine::dump() const {
|
||||
VL_DBG_MSGF(" Awaiting time %" PRIu64 ": ", m_timestep);
|
||||
m_handle.dump();
|
||||
}
|
||||
#endif
|
||||
|
||||
void VlDelayScheduler::resume() {
|
||||
#ifdef VL_DEBUG
|
||||
VL_DEBUG_IF(dump(); VL_DBG_MSGF(" Resuming delayed processes\n"););
|
||||
#endif
|
||||
while (awaitingCurrentTime()) {
|
||||
if (m_queue.front().m_timestep != m_context.time()) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"%Error: Encountered process that should've been resumed at an "
|
||||
"earlier simulation time. Missed a time slot?");
|
||||
}
|
||||
// Move max element in the heap to the end
|
||||
std::pop_heap(m_queue.begin(), m_queue.end());
|
||||
VlCoroutineHandle handle = std::move(m_queue.back().m_handle);
|
||||
m_queue.pop_back();
|
||||
handle.resume();
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t VlDelayScheduler::nextTimeSlot() const {
|
||||
if (empty()) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: There is no next time slot scheduled");
|
||||
}
|
||||
return m_queue.front().m_timestep;
|
||||
}
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
void VlDelayScheduler::dump() const {
|
||||
if (m_queue.empty()) {
|
||||
VL_DBG_MSGF(" No delayed processes:\n");
|
||||
} else {
|
||||
VL_DBG_MSGF(" Delayed processes:\n");
|
||||
for (const auto& susp : m_queue) susp.dump();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// VlTriggerScheduler:: Methods
|
||||
|
||||
void VlTriggerScheduler::resume(const char* eventDescription) {
|
||||
#ifdef VL_DEBUG
|
||||
VL_DEBUG_IF(dump(eventDescription);
|
||||
VL_DBG_MSGF(" Resuming processes waiting for %s\n", eventDescription););
|
||||
#endif
|
||||
for (auto& susp : m_ready) susp.resume();
|
||||
m_ready.clear();
|
||||
commit(eventDescription);
|
||||
}
|
||||
|
||||
void VlTriggerScheduler::commit(const char* eventDescription) {
|
||||
#ifdef VL_DEBUG
|
||||
if (!m_uncommitted.empty()) {
|
||||
VL_DEBUG_IF(
|
||||
VL_DBG_MSGF(" Committing processes waiting for %s:\n", eventDescription);
|
||||
for (const auto& susp
|
||||
: m_uncommitted) {
|
||||
VL_DBG_MSGF(" - ");
|
||||
susp.dump();
|
||||
});
|
||||
}
|
||||
#endif
|
||||
m_ready.reserve(m_ready.size() + m_uncommitted.size());
|
||||
m_ready.insert(m_ready.end(), std::make_move_iterator(m_uncommitted.begin()),
|
||||
std::make_move_iterator(m_uncommitted.end()));
|
||||
m_uncommitted.clear();
|
||||
}
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
void VlTriggerScheduler::dump(const char* eventDescription) const {
|
||||
if (m_ready.empty()) {
|
||||
VL_DBG_MSGF(" No ready processes waiting for %s\n", eventDescription);
|
||||
} else {
|
||||
for (const auto& susp : m_ready) {
|
||||
VL_DBG_MSGF(" Ready processes waiting for %s:\n", eventDescription);
|
||||
VL_DBG_MSGF(" - ");
|
||||
susp.dump();
|
||||
}
|
||||
}
|
||||
if (!m_uncommitted.empty()) {
|
||||
VL_DBG_MSGF(" Uncommitted processes waiting for %s:\n", eventDescription);
|
||||
for (const auto& susp : m_uncommitted) {
|
||||
VL_DBG_MSGF(" - ");
|
||||
susp.dump();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// VlDynamicTriggerScheduler:: Methods
|
||||
|
||||
bool VlDynamicTriggerScheduler::evaluate() {
|
||||
VL_DEBUG_IF(dump(););
|
||||
std::swap(m_suspended, m_evaluated);
|
||||
for (auto& coro : m_evaluated) coro.resume();
|
||||
m_evaluated.clear();
|
||||
return !m_triggered.empty();
|
||||
}
|
||||
|
||||
void VlDynamicTriggerScheduler::doPostUpdates() {
|
||||
VL_DEBUG_IF(if (!m_post.empty())
|
||||
VL_DBG_MSGF(" Doing post updates for processes:\n"); //
|
||||
for (const auto& susp
|
||||
: m_post) {
|
||||
VL_DBG_MSGF(" - ");
|
||||
susp.dump();
|
||||
});
|
||||
for (auto& coro : m_post) coro.resume();
|
||||
m_post.clear();
|
||||
}
|
||||
|
||||
void VlDynamicTriggerScheduler::resume() {
|
||||
VL_DEBUG_IF(if (!m_triggered.empty()) VL_DBG_MSGF(" Resuming processes:\n"); //
|
||||
for (const auto& susp
|
||||
: m_triggered) {
|
||||
VL_DBG_MSGF(" - ");
|
||||
susp.dump();
|
||||
});
|
||||
for (auto& coro : m_triggered) coro.resume();
|
||||
m_triggered.clear();
|
||||
}
|
||||
|
||||
#ifdef VL_DEBUG
|
||||
void VlDynamicTriggerScheduler::dump() const {
|
||||
if (m_suspended.empty()) {
|
||||
VL_DBG_MSGF(" No suspended processes waiting for dynamic trigger evaluation\n");
|
||||
} else {
|
||||
for (const auto& susp : m_suspended) {
|
||||
VL_DBG_MSGF(" Suspended processes waiting for dynamic trigger evaluation:\n");
|
||||
VL_DBG_MSGF(" - ");
|
||||
susp.dump();
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//======================================================================
|
||||
// VlForkSync:: Methods
|
||||
|
||||
void VlForkSync::done(const char* filename, int lineno) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF(" Process forked at %s:%d finished\n", filename, lineno););
|
||||
if (m_join->m_counter > 0) m_join->m_counter--;
|
||||
if (m_join->m_counter == 0) m_join->m_susp.resume();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// VlCoroutine:: Methods
|
||||
|
||||
VlCoroutine::VlPromise::~VlPromise() {
|
||||
// Indicate to the return object that the coroutine has finished or been destroyed
|
||||
if (m_corop) m_corop->m_promisep = nullptr;
|
||||
// If there is a continuation, destroy it
|
||||
if (m_continuation) m_continuation.destroy();
|
||||
}
|
||||
|
||||
std::suspend_never VlCoroutine::VlPromise::final_suspend() noexcept {
|
||||
// Indicate to the return object that the coroutine has finished
|
||||
if (m_corop) {
|
||||
m_corop->m_promisep = nullptr;
|
||||
// Forget the return value, we won't need it and it won't be able to let us know if
|
||||
// it's destroyed
|
||||
m_corop = nullptr;
|
||||
}
|
||||
// If there is a continuation, resume it
|
||||
if (m_continuation) {
|
||||
m_continuation();
|
||||
m_continuation = nullptr;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
@@ -0,0 +1,431 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
// Copyright 2022 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 timing header
|
||||
///
|
||||
/// This file is included automatically by Verilator in some of the C++ files
|
||||
/// it generates if timing 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_TIMING_H_
|
||||
#define VERILATOR_VERILATED_TIMING_H_
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
// clang-format off
|
||||
// Some preprocessor magic to support both Clang and GCC coroutines with both libc++ and libstdc++
|
||||
#if defined _LIBCPP_VERSION // libc++
|
||||
# if __clang_major__ > 13 // Clang > 13 warns that coroutine types in std::experimental are deprecated
|
||||
# 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
|
||||
# if defined __clang__ && defined __GLIBCXX__
|
||||
# define __cpp_impl_coroutine 1 // Clang doesn't define this, but it's needed for libstdc++
|
||||
# endif
|
||||
# include <coroutine>
|
||||
# if __clang_major__ < 14
|
||||
namespace std { // Bring coroutine library into std::experimental, as Clang < 14 expects it to be there
|
||||
namespace experimental {
|
||||
using namespace std;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// Placeholder for compiling with --protect-ids
|
||||
#define VL_UNKNOWN "<unknown>"
|
||||
|
||||
//=============================================================================
|
||||
// VlFileLineDebug stores a SystemVerilog source code location. Used in VlCoroutineHandle for
|
||||
// debugging purposes.
|
||||
|
||||
class VlFileLineDebug final {
|
||||
// MEMBERS
|
||||
#ifdef VL_DEBUG
|
||||
const char* m_filename = nullptr;
|
||||
int m_lineno = 0;
|
||||
#endif
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
// Construct
|
||||
VlFileLineDebug() = default;
|
||||
VlFileLineDebug(const char* filename, int lineno)
|
||||
#ifdef VL_DEBUG
|
||||
: m_filename{filename}
|
||||
, m_lineno{lineno}
|
||||
#endif
|
||||
{
|
||||
}
|
||||
|
||||
// METHODS
|
||||
#ifdef VL_DEBUG
|
||||
const char* filename() const { return m_filename; }
|
||||
int lineno() const { return m_lineno; }
|
||||
#endif
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlCoroutineHandle is a non-copyable (but movable) coroutine handle. On resume, the handle is
|
||||
// cleared, as we assume that either the coroutine has finished and deleted itself, or, if it got
|
||||
// suspended, another VlCoroutineHandle was created to manage it.
|
||||
|
||||
class VlCoroutineHandle final {
|
||||
VL_UNCOPYABLE(VlCoroutineHandle);
|
||||
|
||||
// MEMBERS
|
||||
std::coroutine_handle<> m_coro; // The wrapped coroutine handle
|
||||
VlFileLineDebug m_fileline;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
// Construct
|
||||
VlCoroutineHandle()
|
||||
: m_coro{nullptr} {}
|
||||
VlCoroutineHandle(std::coroutine_handle<> coro, VlFileLineDebug fileline)
|
||||
: m_coro{coro}
|
||||
, m_fileline{fileline} {}
|
||||
// Move the handle, leaving a nullptr
|
||||
VlCoroutineHandle(VlCoroutineHandle&& moved)
|
||||
: m_coro{std::exchange(moved.m_coro, nullptr)}
|
||||
, m_fileline{moved.m_fileline} {}
|
||||
// Destroy if the handle isn't null
|
||||
~VlCoroutineHandle() {
|
||||
// Usually these coroutines should get resumed; we only need to clean up if we destroy a
|
||||
// model with some coroutines suspended
|
||||
if (VL_UNLIKELY(m_coro)) m_coro.destroy();
|
||||
}
|
||||
// METHODS
|
||||
// Move the handle, leaving a null handle
|
||||
auto& operator=(VlCoroutineHandle&& moved) {
|
||||
m_coro = std::exchange(moved.m_coro, nullptr);
|
||||
return *this;
|
||||
}
|
||||
// Resume the coroutine if the handle isn't null
|
||||
void resume();
|
||||
#ifdef VL_DEBUG
|
||||
void dump() const;
|
||||
#endif
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlDelayScheduler stores coroutines to be resumed at a certain simulation time. If the current
|
||||
// time is equal to a coroutine's resume time, the coroutine gets resumed.
|
||||
|
||||
class VlDelayScheduler final {
|
||||
// TYPES
|
||||
struct VlDelayedCoroutine {
|
||||
uint64_t m_timestep; // Simulation time when the coroutine should be resumed
|
||||
VlCoroutineHandle m_handle; // The suspended coroutine to be resumed
|
||||
|
||||
// Comparison operator for std::push_heap(), std::pop_heap()
|
||||
bool operator<(const VlDelayedCoroutine& other) const {
|
||||
return m_timestep > other.m_timestep;
|
||||
}
|
||||
#ifdef VL_DEBUG
|
||||
void dump() const;
|
||||
#endif
|
||||
};
|
||||
using VlDelayedCoroutineQueue = std::vector<VlDelayedCoroutine>;
|
||||
|
||||
// MEMBERS
|
||||
VerilatedContext& m_context;
|
||||
VlDelayedCoroutineQueue m_queue; // Coroutines to be restored at a certain simulation time
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit VlDelayScheduler(VerilatedContext& context)
|
||||
: m_context{context} {}
|
||||
// METHODS
|
||||
// Resume coroutines waiting for the current simulation time
|
||||
void resume();
|
||||
// Returns the simulation time of the next time slot (aborts if there are no delayed
|
||||
// coroutines)
|
||||
uint64_t nextTimeSlot() const;
|
||||
// Are there no delayed coroutines awaiting?
|
||||
bool empty() const { return m_queue.empty(); }
|
||||
// Are there coroutines to resume at the current simulation time?
|
||||
bool awaitingCurrentTime() const {
|
||||
return !empty() && m_queue.front().m_timestep <= m_context.time();
|
||||
}
|
||||
#ifdef VL_DEBUG
|
||||
void dump() const;
|
||||
#endif
|
||||
// Used by coroutines for co_awaiting a certain simulation time
|
||||
auto delay(uint64_t delay, const char* filename = VL_UNKNOWN, int lineno = 0) {
|
||||
struct Awaitable {
|
||||
VlDelayedCoroutineQueue& queue;
|
||||
uint64_t delay;
|
||||
VlFileLineDebug fileline;
|
||||
|
||||
bool await_ready() const { return false; } // Always suspend
|
||||
void await_suspend(std::coroutine_handle<> coro) {
|
||||
queue.push_back({delay, VlCoroutineHandle{coro, fileline}});
|
||||
// Move last element to the proper place in the max-heap
|
||||
std::push_heap(queue.begin(), queue.end());
|
||||
}
|
||||
void await_resume() const {}
|
||||
};
|
||||
return Awaitable{m_queue, m_context.time() + delay, VlFileLineDebug{filename, lineno}};
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlTriggerScheduler stores coroutines to be resumed by a trigger. It does not keep track of its
|
||||
// trigger, relying on calling code to resume when appropriate. Coroutines are kept in two stages
|
||||
// - 'uncommitted' and 'ready'. Whenever a coroutine is suspended, it lands in the 'uncommitted'
|
||||
// stage. Only when commit() is called, these coroutines get moved to the 'ready' stage. That's
|
||||
// when they can be resumed. This is done to avoid resuming processes before they start waiting.
|
||||
|
||||
class VlTriggerScheduler final {
|
||||
// TYPES
|
||||
using VlCoroutineVec = std::vector<VlCoroutineHandle>;
|
||||
|
||||
// MEMBERS
|
||||
VlCoroutineVec m_uncommitted; // Coroutines suspended before commit() was called
|
||||
// (not resumable)
|
||||
VlCoroutineVec m_ready; // Coroutines that can be resumed (all coros from m_uncommitted are
|
||||
// moved here in commit())
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
// Resumes all coroutines from the 'ready' stage
|
||||
void resume(const char* eventDescription = VL_UNKNOWN);
|
||||
// Moves all coroutines from m_uncommitted to m_ready
|
||||
void commit(const char* eventDescription = VL_UNKNOWN);
|
||||
// Are there no coroutines awaiting?
|
||||
bool empty() const { return m_ready.empty() && m_uncommitted.empty(); }
|
||||
#ifdef VL_DEBUG
|
||||
void dump(const char* eventDescription) const;
|
||||
#endif
|
||||
// Used by coroutines for co_awaiting a certain trigger
|
||||
auto trigger(const char* eventDescription = VL_UNKNOWN, const char* filename = VL_UNKNOWN,
|
||||
int lineno = 0) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n",
|
||||
eventDescription, filename, lineno););
|
||||
struct Awaitable {
|
||||
VlCoroutineVec& suspended; // Coros waiting on trigger
|
||||
VlFileLineDebug fileline;
|
||||
|
||||
bool await_ready() const { return false; } // Always suspend
|
||||
void await_suspend(std::coroutine_handle<> coro) {
|
||||
suspended.emplace_back(coro, fileline);
|
||||
}
|
||||
void await_resume() const {}
|
||||
};
|
||||
return Awaitable{m_uncommitted, VlFileLineDebug{filename, lineno}};
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlDynamicTriggerScheduler is used for cases where triggers cannot be statically referenced and
|
||||
// evaluated. Coroutines that make use of this scheduler must adhere to a certain procedure:
|
||||
// __Vtrigger = 0;
|
||||
// <locals and inits required for trigger eval>
|
||||
// while (!__Vtrigger) {
|
||||
// co_await __VdynSched.evaluation();
|
||||
// <pre updates>;
|
||||
// __Vtrigger = <trigger eval>;
|
||||
// [optionally] co_await __VdynSched.postUpdate();
|
||||
// <post updates>;
|
||||
// }
|
||||
// co_await __VdynSched.resumption();
|
||||
// The coroutines get resumed at trigger evaluation time, evaluate their local triggers, optionally
|
||||
// await the post update step, and if the trigger is set, await proper resumption in the 'act' eval
|
||||
// step.
|
||||
|
||||
class VlDynamicTriggerScheduler final {
|
||||
// TYPES
|
||||
using VlCoroutineVec = std::vector<VlCoroutineHandle>;
|
||||
|
||||
// MEMBERS
|
||||
VlCoroutineVec m_suspended; // Suspended coroutines awaiting trigger evaluation
|
||||
VlCoroutineVec m_evaluated; // Coroutines currently being evaluated (for evaluate())
|
||||
VlCoroutineVec m_triggered; // Coroutines whose triggers were set, and are awaiting resumption
|
||||
VlCoroutineVec m_post; // Coroutines awaiting the post update step (only relevant for triggers
|
||||
// with destructive post updates, e.g. named events)
|
||||
|
||||
// METHODS
|
||||
auto awaitable(VlCoroutineVec& queue, const char* filename, int lineno) {
|
||||
struct Awaitable {
|
||||
VlCoroutineVec& suspended; // Coros waiting on trigger
|
||||
VlFileLineDebug fileline;
|
||||
|
||||
bool await_ready() const { return false; } // Always suspend
|
||||
void await_suspend(std::coroutine_handle<> coro) {
|
||||
suspended.emplace_back(coro, fileline);
|
||||
}
|
||||
void await_resume() const {}
|
||||
};
|
||||
return Awaitable{queue, VlFileLineDebug{filename, lineno}};
|
||||
}
|
||||
|
||||
public:
|
||||
// Evaluates all dynamic triggers (resumed coroutines that co_await evaluation())
|
||||
bool evaluate();
|
||||
// Runs post updates for all dynamic triggers (resumes coroutines that co_await postUpdate())
|
||||
void doPostUpdates();
|
||||
// Resumes all coroutines whose triggers are set (those that co_await resumption())
|
||||
void resume();
|
||||
#ifdef VL_DEBUG
|
||||
void dump() const;
|
||||
#endif
|
||||
// Used by coroutines for co_awaiting trigger evaluation
|
||||
auto evaluation(const char* eventDescription, const char* filename, int lineno) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n",
|
||||
eventDescription, filename, lineno););
|
||||
return awaitable(m_suspended, filename, lineno);
|
||||
}
|
||||
// Used by coroutines for co_awaiting the trigger post update step
|
||||
auto postUpdate(const char* eventDescription, const char* filename, int lineno) {
|
||||
VL_DEBUG_IF(
|
||||
VL_DBG_MSGF(" Process waiting for %s at %s:%d awaiting the post update step\n",
|
||||
eventDescription, filename, lineno););
|
||||
return awaitable(m_post, filename, lineno);
|
||||
}
|
||||
// Used by coroutines for co_awaiting the resumption step (in 'act' eval)
|
||||
auto resumption(const char* eventDescription, const char* filename, int lineno) {
|
||||
VL_DEBUG_IF(VL_DBG_MSGF(" Process waiting for %s at %s:%d awaiting resumption\n",
|
||||
eventDescription, filename, lineno););
|
||||
return awaitable(m_triggered, filename, lineno);
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlNow is a helper awaitable type that always suspends, and then immediately resumes a coroutine.
|
||||
// Allows forcing the move of coroutine locals to the heap.
|
||||
|
||||
struct VlNow {
|
||||
bool await_ready() const { return false; } // Always suspend
|
||||
bool await_suspend(std::coroutine_handle<>) const { return false; } // Resume immediately
|
||||
void await_resume() const {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlForever is a helper awaitable type for suspending coroutines forever. Used for constant
|
||||
// wait statements.
|
||||
|
||||
struct VlForever {
|
||||
bool await_ready() const { return false; } // Always suspend
|
||||
void await_suspend(std::coroutine_handle<> coro) const { coro.destroy(); }
|
||||
void await_resume() const {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlForkSync is used to manage fork..join and fork..join_any constructs.
|
||||
|
||||
class VlForkSync final {
|
||||
// VlJoin stores the handle of a suspended coroutine that did a fork..join or fork..join_any.
|
||||
// If the counter reaches 0, the suspended coroutine shall be resumed.
|
||||
struct VlJoin {
|
||||
size_t m_counter = 0; // When reaches 0, resume suspended coroutine
|
||||
VlCoroutineHandle m_susp; // Coroutine to resume
|
||||
};
|
||||
|
||||
// The join info is shared among all forked processes
|
||||
std::shared_ptr<VlJoin> m_join;
|
||||
|
||||
public:
|
||||
// Create the join object and set the counter to the specified number
|
||||
void init(size_t count) { m_join.reset(new VlJoin{count, {}}); }
|
||||
// Called whenever any of the forked processes finishes. If the join counter reaches 0, the
|
||||
// main process gets resumed
|
||||
void done(const char* filename = VL_UNKNOWN, int lineno = 0);
|
||||
// Used by coroutines for co_awaiting a join
|
||||
auto join(const char* filename = VL_UNKNOWN, int lineno = 0) {
|
||||
assert(m_join);
|
||||
VL_DEBUG_IF(
|
||||
VL_DBG_MSGF(" Awaiting join of fork at: %s:%d\n", filename, lineno););
|
||||
struct Awaitable {
|
||||
const std::shared_ptr<VlJoin> join; // Join to await on
|
||||
VlFileLineDebug fileline;
|
||||
|
||||
bool await_ready() { return join->m_counter == 0; } // Suspend if join still exists
|
||||
void await_suspend(std::coroutine_handle<> coro) { join->m_susp = {coro, fileline}; }
|
||||
void await_resume() const {}
|
||||
};
|
||||
return Awaitable{m_join, VlFileLineDebug{filename, lineno}};
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VlCoroutine
|
||||
// Return value of a coroutine. Used for chaining coroutine suspension/resumption.
|
||||
|
||||
class VlCoroutine final {
|
||||
private:
|
||||
// TYPES
|
||||
struct VlPromise {
|
||||
std::coroutine_handle<> m_continuation; // Coroutine to resume after this one finishes
|
||||
VlCoroutine* m_corop = nullptr; // Pointer to the coroutine return object
|
||||
|
||||
~VlPromise();
|
||||
|
||||
VlCoroutine get_return_object() { return {this}; }
|
||||
|
||||
// Never suspend at the start of the coroutine
|
||||
std::suspend_never initial_suspend() const { return {}; }
|
||||
|
||||
// Never suspend at the end of the coroutine (thanks to this, the coroutine will clean up
|
||||
// after itself)
|
||||
std::suspend_never final_suspend() noexcept;
|
||||
|
||||
void unhandled_exception() const { std::abort(); }
|
||||
void return_void() const {}
|
||||
};
|
||||
|
||||
// MEMBERS
|
||||
VlPromise* m_promisep; // The promise created for this coroutine
|
||||
|
||||
public:
|
||||
// TYPES
|
||||
using promise_type = VlPromise; // promise_type has to be public
|
||||
|
||||
// CONSTRUCTORS
|
||||
// Construct
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VlCoroutine(VlPromise* promisep)
|
||||
: m_promisep{promisep} {
|
||||
m_promisep->m_corop = this;
|
||||
}
|
||||
// Move. Update the pointers each time the return object is moved
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VlCoroutine(VlCoroutine&& other)
|
||||
: m_promisep{std::exchange(other.m_promisep, nullptr)} {
|
||||
if (m_promisep) m_promisep->m_corop = this;
|
||||
}
|
||||
~VlCoroutine() {
|
||||
// Indicate to the promise that the return object is gone
|
||||
if (m_promisep) m_promisep->m_corop = nullptr;
|
||||
}
|
||||
|
||||
// METHODS
|
||||
// Suspend the awaiter if the coroutine is suspended (the promise exists)
|
||||
bool await_ready() const noexcept { return !m_promisep; }
|
||||
// Set the awaiting coroutine as the continuation of the current coroutine
|
||||
void await_suspend(std::coroutine_handle<> coro) { m_promisep->m_continuation = coro; }
|
||||
void await_resume() const noexcept {}
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
+168
-146
@@ -24,21 +24,6 @@
|
||||
|
||||
// clang-format off
|
||||
|
||||
// In FST mode, VL_TRACE_THREADED enables offloading, but only if we also have
|
||||
// the FST writer thread. This means with --trace-threads 1, we get the FST
|
||||
// writer thread only, and with --trace-threads 2 we get offloading as well
|
||||
#if defined(VL_TRACE_FST_WRITER_THREAD) && defined(VL_TRACE_THREADED)
|
||||
# define VL_TRACE_OFFLOAD
|
||||
#endif
|
||||
// VCD tracing can happen fully in parallel
|
||||
#if defined(VM_TRACE_VCD) && VM_TRACE_VCD && defined(VL_TRACE_THREADED)
|
||||
# define VL_TRACE_PARALLEL
|
||||
#endif
|
||||
|
||||
#if defined(VL_TRACE_PARALLEL) && defined(VL_TRACE_OFFLOAD)
|
||||
# error "Cannot have VL_TRACE_PARALLEL and VL_TRACE_OFFLOAD together"
|
||||
#endif
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_trace_defs.h"
|
||||
|
||||
@@ -47,24 +32,26 @@
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
# include <deque>
|
||||
# include <thread>
|
||||
#endif
|
||||
#include <deque>
|
||||
#include <thread>
|
||||
|
||||
// clang-format on
|
||||
|
||||
class VlThreadPool;
|
||||
template <class T_Trace, class T_Buffer> class VerilatedTraceBuffer;
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceBuffer;
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceOffloadBuffer;
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
//=============================================================================
|
||||
// Offloaded tracing
|
||||
|
||||
// A simple synchronized first in first out queue
|
||||
template <class T> class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug
|
||||
template <class T>
|
||||
class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug
|
||||
private:
|
||||
mutable VerilatedMutex m_mutex; // Protects m_queue
|
||||
std::condition_variable_any m_cv;
|
||||
@@ -120,6 +107,7 @@ public:
|
||||
CHG_QDATA = 0x5,
|
||||
CHG_WDATA = 0x6,
|
||||
CHG_DOUBLE = 0x8,
|
||||
CHG_EVENT = 0x9,
|
||||
// TODO: full..
|
||||
TIME_CHANGE = 0xc,
|
||||
TRACE_BUFFER = 0xd,
|
||||
@@ -127,29 +115,48 @@ public:
|
||||
SHUTDOWN = 0xf // Shutdown worker thread, also marks end of buffer
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedTraceConfig
|
||||
|
||||
// Simple data representing trace configuration required by generated models.
|
||||
class VerilatedTraceConfig final {
|
||||
public:
|
||||
const bool m_useParallel; // Use parallel tracing
|
||||
const bool m_useOffloading; // Offloading trace rendering
|
||||
const bool m_useFstWriterThread; // Use the separate FST writer thread
|
||||
|
||||
VerilatedTraceConfig(bool useParallel, bool useOffloading, bool useFstWriterThread)
|
||||
: m_useParallel{useParallel}
|
||||
, m_useOffloading{useOffloading}
|
||||
, m_useFstWriterThread{useFstWriterThread} {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedTrace
|
||||
|
||||
// T_Trace is the format specific subclass of VerilatedTrace.
|
||||
// T_Buffer is the format specific subclass of VerilatedTraceBuffer.
|
||||
template <class T_Trace, class T_Buffer> class VerilatedTrace VL_NOT_FINAL {
|
||||
// Give the buffer (both base and derived) access to the private bits
|
||||
friend VerilatedTraceBuffer<T_Trace, T_Buffer>;
|
||||
friend T_Buffer;
|
||||
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
template <class T_Trace, class T_Buffer>
|
||||
class VerilatedTrace VL_NOT_FINAL {
|
||||
public:
|
||||
using Buffer = T_Buffer;
|
||||
using Buffer = VerilatedTraceBuffer<T_Buffer>;
|
||||
using OffloadBuffer = VerilatedTraceOffloadBuffer<T_Buffer>;
|
||||
|
||||
//=========================================================================
|
||||
// Generic tracing internals
|
||||
|
||||
using initCb_t = void (*)(void*, T_Trace*, uint32_t); // Type of init callbacks
|
||||
using dumpCb_t = void (*)(void*, Buffer*); // Type of dump callbacks
|
||||
using dumpOffloadCb_t = void (*)(void*, OffloadBuffer*); // Type of offload dump callbacks
|
||||
using cleanupCb_t = void (*)(void*, T_Trace*); // Type of cleanup callbacks
|
||||
|
||||
private:
|
||||
// Give the buffer (both base and derived) access to the private bits
|
||||
friend T_Buffer;
|
||||
friend Buffer;
|
||||
friend OffloadBuffer;
|
||||
|
||||
struct CallbackRecord {
|
||||
// Note: would make these fields const, but some old STL implementations
|
||||
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
|
||||
@@ -158,6 +165,7 @@ private:
|
||||
union { // The callback
|
||||
initCb_t m_initCb;
|
||||
dumpCb_t m_dumpCb;
|
||||
dumpOffloadCb_t m_dumpOffloadCb;
|
||||
cleanupCb_t m_cleanupCb;
|
||||
};
|
||||
void* m_userp; // The user pointer to pass to the callback (the symbol table)
|
||||
@@ -167,12 +175,17 @@ private:
|
||||
CallbackRecord(dumpCb_t cb, void* userp)
|
||||
: m_dumpCb{cb}
|
||||
, m_userp{userp} {}
|
||||
CallbackRecord(dumpOffloadCb_t cb, void* userp)
|
||||
: m_dumpOffloadCb{cb}
|
||||
, m_userp{userp} {}
|
||||
CallbackRecord(cleanupCb_t cb, void* userp)
|
||||
: m_cleanupCb{cb}
|
||||
, m_userp{userp} {}
|
||||
};
|
||||
|
||||
#ifdef VL_TRACE_PARALLEL
|
||||
bool m_offload = false; // Use the offload thread
|
||||
bool m_parallel = false; // Use parallel tracing
|
||||
|
||||
struct ParallelWorkerData {
|
||||
const dumpCb_t m_cb; // The callback
|
||||
void* const m_userp; // The use pointer to pass to the callback
|
||||
@@ -192,21 +205,18 @@ private:
|
||||
|
||||
// Passed a ParallelWorkerData*, second argument is ignored
|
||||
static void parallelWorkerTask(void*, bool);
|
||||
#endif
|
||||
|
||||
using ParallelCallbackMap = std::unordered_map<VlThreadPool*, std::vector<CallbackRecord>>;
|
||||
|
||||
protected:
|
||||
uint32_t* m_sigs_oldvalp = nullptr; // Previous value store
|
||||
EData* m_sigs_enabledp = nullptr; // Bit vector of enabled codes (nullptr = all on)
|
||||
private:
|
||||
uint64_t m_timeLastDump = 0; // Last time we did a dump
|
||||
std::vector<bool> m_sigs_enabledVec; // Staging for m_sigs_enabledp
|
||||
std::vector<CallbackRecord> m_initCbs; // Routines to initialize tracing
|
||||
ParallelCallbackMap m_fullCbs; // Routines to perform full dump
|
||||
ParallelCallbackMap m_chgCbs; // Routines to perform incremental dump
|
||||
std::vector<CallbackRecord> m_fullCbs; // Routines to perform full dump
|
||||
std::vector<CallbackRecord> m_fullOffloadCbs; // Routines to perform offloaded full dump
|
||||
std::vector<CallbackRecord> m_chgCbs; // Routines to perform incremental dump
|
||||
std::vector<CallbackRecord> m_chgOffloadCbs; // Routines to perform offloaded incremental dump
|
||||
std::vector<CallbackRecord> m_cleanupCbs; // Routines to call at the end of dump
|
||||
std::vector<VlThreadPool*> m_threadPoolps; // All thread pools, in insertion order
|
||||
bool m_fullDump = true; // Whether a full dump is required on the next call to 'dump'
|
||||
uint32_t m_nextCode = 0; // Next code number to assign
|
||||
uint32_t m_numSignals = 0; // Number of distinct signals
|
||||
@@ -216,24 +226,26 @@ private:
|
||||
char m_scopeEscape = '.';
|
||||
double m_timeRes = 1e-9; // Time resolution (ns/ms etc)
|
||||
double m_timeUnit = 1e-0; // Time units (ns/ms etc)
|
||||
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)
|
||||
VerilatedContext* m_contextp = nullptr; // The context used by the traced models
|
||||
std::unordered_set<const VerilatedModel*> m_models; // The collection of models being traced
|
||||
|
||||
void addThreadPool(VlThreadPool* threadPoolp) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
|
||||
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord& cbRec)
|
||||
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord&& cbRec)
|
||||
VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
|
||||
// Equivalent to 'this' but is of the sub-type 'T_Trace*'. Use 'self()->'
|
||||
// to access duck-typed functions to avoid a virtual function call.
|
||||
T_Trace* self() { return static_cast<T_Trace*>(this); }
|
||||
|
||||
void runParallelCallbacks(const ParallelCallbackMap& cbMap);
|
||||
void runCallbacks(const std::vector<CallbackRecord>& cbVec);
|
||||
void runOffloadedCallbacks(const std::vector<CallbackRecord>& cbVec);
|
||||
|
||||
// Flush any remaining data for this file
|
||||
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
|
||||
// Close the file on termination
|
||||
static void onExit(void* selfp) VL_MT_UNSAFE_ONE;
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
// Number of total offload buffers that have been allocated
|
||||
uint32_t m_numOffloadBuffers = 0;
|
||||
// Size of offload buffers
|
||||
@@ -264,7 +276,6 @@ private:
|
||||
|
||||
// Shut down and join worker, if it's running, otherwise do nothing
|
||||
void shutdownOffloadWorker();
|
||||
#endif
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedTrace);
|
||||
@@ -279,7 +290,6 @@ protected:
|
||||
uint32_t numSignals() const { return m_numSignals; }
|
||||
uint32_t maxBits() const { return m_maxBits; }
|
||||
void fullDump(bool value) { m_fullDump = value; }
|
||||
uint64_t timeLastDump() { return m_timeLastDump; }
|
||||
|
||||
double timeRes() const { return m_timeRes; }
|
||||
double timeUnit() const { return m_timeUnit; }
|
||||
@@ -300,6 +310,9 @@ protected:
|
||||
void closeBase();
|
||||
void flushBase();
|
||||
|
||||
bool offload() const { return m_offload; }
|
||||
bool parallel() const { return m_parallel; }
|
||||
|
||||
//=========================================================================
|
||||
// Virtual functions to be provided by the format specific implementation
|
||||
|
||||
@@ -315,6 +328,9 @@ protected:
|
||||
virtual Buffer* getTraceBuffer() = 0;
|
||||
virtual void commitTraceBuffer(Buffer*) = 0;
|
||||
|
||||
// Configure sub-class
|
||||
virtual void configure(const VerilatedTraceConfig&) = 0;
|
||||
|
||||
public:
|
||||
//=========================================================================
|
||||
// External interface to client code
|
||||
@@ -341,9 +357,12 @@ public:
|
||||
//=========================================================================
|
||||
// Non-hot path internal interface to Verilator generated code
|
||||
|
||||
void addModel(VerilatedModel*) VL_MT_SAFE_EXCLUDES(m_mutex);
|
||||
void addInitCb(initCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addFullCb(dumpCb_t cb, void* userp, VlThreadPool* = nullptr) VL_MT_SAFE;
|
||||
void addChgCb(dumpCb_t cb, void* userp, VlThreadPool* = nullptr) VL_MT_SAFE;
|
||||
void addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE;
|
||||
void addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE;
|
||||
|
||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
||||
@@ -355,33 +374,26 @@ public:
|
||||
//=============================================================================
|
||||
// VerilatedTraceBuffer
|
||||
|
||||
// T_Trace is the format specific subclass of VerilatedTrace.
|
||||
// T_Buffer is the format specific subclass of VerilatedTraceBuffer.
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
// The format-specific hot-path methods use duck-typing via T_Buffer for performance.
|
||||
template <class T_Trace, class T_Buffer> class VerilatedTraceBuffer VL_NOT_FINAL {
|
||||
friend T_Trace; // Give the trace file access to the private bits
|
||||
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceBuffer VL_NOT_FINAL : public T_Buffer {
|
||||
protected:
|
||||
T_Trace& m_owner; // The VerilatedTrace subclass that owns this buffer
|
||||
// Type of the owner trace file
|
||||
using Trace = typename std::remove_cv<
|
||||
typename std::remove_reference<decltype(T_Buffer::m_owner)>::type>::type;
|
||||
|
||||
// Previous value store
|
||||
uint32_t* const m_sigs_oldvalp = m_owner.m_sigs_oldvalp;
|
||||
// Bit vector of enabled codes (nullptr = all on)
|
||||
EData* const m_sigs_enabledp = m_owner.m_sigs_enabledp;
|
||||
static_assert(std::has_virtual_destructor<T_Buffer>::value, "");
|
||||
static_assert(std::is_base_of<VerilatedTrace<Trace, T_Buffer>, Trace>::value, "");
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
// Write pointer into current buffer
|
||||
uint32_t* m_offloadBufferWritep = m_owner.m_offloadBufferWritep;
|
||||
// End of offload buffer
|
||||
uint32_t* const m_offloadBufferEndp = m_owner.m_offloadBufferEndp;
|
||||
#endif
|
||||
friend Trace; // Give the trace file access to the private bits
|
||||
friend std::default_delete<VerilatedTraceBuffer<T_Buffer>>;
|
||||
|
||||
// Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->'
|
||||
// to access duck-typed functions to avoid a virtual function call.
|
||||
inline T_Buffer* self() { return static_cast<T_Buffer*>(this); }
|
||||
uint32_t* const m_sigs_oldvalp; // Previous value store
|
||||
EData* const m_sigs_enabledp; // Bit vector of enabled codes (nullptr = all on)
|
||||
|
||||
explicit VerilatedTraceBuffer(T_Trace& owner);
|
||||
virtual ~VerilatedTraceBuffer() = default;
|
||||
explicit VerilatedTraceBuffer(Trace& owner);
|
||||
~VerilatedTraceBuffer() override = default;
|
||||
|
||||
public:
|
||||
//=========================================================================
|
||||
@@ -401,7 +413,7 @@ public:
|
||||
// duck-typed void emitWData(uint32_t code, const WData* newvalp, int bits) = 0;
|
||||
// duck-typed void emitDouble(uint32_t code, double newval) = 0;
|
||||
|
||||
VL_ATTR_ALWINLINE inline uint32_t* oldp(uint32_t code) { return m_sigs_oldvalp + code; }
|
||||
VL_ATTR_ALWINLINE uint32_t* oldp(uint32_t code) { return m_sigs_oldvalp + code; }
|
||||
|
||||
// Write to previous value buffer value and emit trace entry.
|
||||
void fullBit(uint32_t* oldp, CData newval);
|
||||
@@ -411,94 +423,34 @@ public:
|
||||
void fullQData(uint32_t* oldp, QData newval, int bits);
|
||||
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
|
||||
void fullDouble(uint32_t* oldp, double newval);
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
// Offloaded tracing. Just dump everything in the offload buffer
|
||||
inline void chgBit(uint32_t code, CData newval) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_BIT_0 | newval;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
inline void chgCData(uint32_t code, CData newval, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_CDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep[2] = newval;
|
||||
m_offloadBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
inline void chgSData(uint32_t code, SData newval, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_SDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep[2] = newval;
|
||||
m_offloadBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
inline void chgIData(uint32_t code, IData newval, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_IDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep[2] = newval;
|
||||
m_offloadBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
inline void chgQData(uint32_t code, QData newval, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_QDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
*reinterpret_cast<QData*>(m_offloadBufferWritep + 2) = newval;
|
||||
m_offloadBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
inline void chgWData(uint32_t code, const WData* newvalp, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_WDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_offloadBufferWritep++ = newvalp[i]; }
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
inline void chgDouble(uint32_t code, double newval) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_DOUBLE;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
*reinterpret_cast<double*>(m_offloadBufferWritep + 2) = newval;
|
||||
m_offloadBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
|
||||
#define chgBit chgBitImpl
|
||||
#define chgCData chgCDataImpl
|
||||
#define chgSData chgSDataImpl
|
||||
#define chgIData chgIDataImpl
|
||||
#define chgQData chgQDataImpl
|
||||
#define chgWData chgWDataImpl
|
||||
#define chgDouble chgDoubleImpl
|
||||
#endif
|
||||
void fullEvent(uint32_t* oldp, VlEvent newval);
|
||||
|
||||
// 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
|
||||
// thread and are called chg*Impl
|
||||
|
||||
// Check previous dumped value of signal. If changed, then emit trace entry
|
||||
VL_ATTR_ALWINLINE inline void chgBit(uint32_t* oldp, CData newval) {
|
||||
VL_ATTR_ALWINLINE void chgBit(uint32_t* oldp, CData newval) {
|
||||
const uint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullBit(oldp, newval);
|
||||
}
|
||||
VL_ATTR_ALWINLINE inline void chgCData(uint32_t* oldp, CData newval, int bits) {
|
||||
VL_ATTR_ALWINLINE void chgCData(uint32_t* oldp, CData newval, int bits) {
|
||||
const uint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits);
|
||||
}
|
||||
VL_ATTR_ALWINLINE inline void chgSData(uint32_t* oldp, SData newval, int bits) {
|
||||
VL_ATTR_ALWINLINE void chgSData(uint32_t* oldp, SData newval, int bits) {
|
||||
const uint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits);
|
||||
}
|
||||
VL_ATTR_ALWINLINE inline void chgIData(uint32_t* oldp, IData newval, int bits) {
|
||||
VL_ATTR_ALWINLINE void chgIData(uint32_t* oldp, IData newval, int bits) {
|
||||
const uint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits);
|
||||
}
|
||||
VL_ATTR_ALWINLINE inline void chgQData(uint32_t* oldp, QData newval, int bits) {
|
||||
VL_ATTR_ALWINLINE void chgQData(uint32_t* oldp, QData newval, int bits) {
|
||||
const uint64_t diff = *reinterpret_cast<QData*>(oldp) ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits);
|
||||
}
|
||||
VL_ATTR_ALWINLINE inline void chgWData(uint32_t* oldp, const WData* newvalp, int bits) {
|
||||
VL_ATTR_ALWINLINE void chgWData(uint32_t* oldp, const WData* newvalp, int bits) {
|
||||
for (int i = 0; i < (bits + 31) / 32; ++i) {
|
||||
if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) {
|
||||
fullWData(oldp, newvalp, bits);
|
||||
@@ -506,20 +458,90 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
VL_ATTR_ALWINLINE inline void chgDouble(uint32_t* oldp, double newval) {
|
||||
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEvent newval) { fullEvent(oldp, newval); }
|
||||
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
#undef chgBit
|
||||
#undef chgCData
|
||||
#undef chgSData
|
||||
#undef chgIData
|
||||
#undef chgQData
|
||||
#undef chgWData
|
||||
#undef chgDouble
|
||||
#endif
|
||||
//=============================================================================
|
||||
// VerilatedTraceOffloadBuffer
|
||||
|
||||
// T_Buffer is the format specific base class of VerilatedTraceBuffer.
|
||||
// The format-specific hot-path methods use duck-typing via T_Buffer for performance.
|
||||
template <class T_Buffer>
|
||||
class VerilatedTraceOffloadBuffer final : public VerilatedTraceBuffer<T_Buffer> {
|
||||
using typename VerilatedTraceBuffer<T_Buffer>::Trace;
|
||||
|
||||
friend Trace; // Give the trace file access to the private bits
|
||||
|
||||
uint32_t* m_offloadBufferWritep; // Write pointer into current buffer
|
||||
uint32_t* const m_offloadBufferEndp; // End of offload buffer
|
||||
|
||||
explicit VerilatedTraceOffloadBuffer(Trace& owner);
|
||||
~VerilatedTraceOffloadBuffer() override = default;
|
||||
|
||||
public:
|
||||
//=========================================================================
|
||||
// Hot path internal interface to Verilator generated code
|
||||
|
||||
// Offloaded tracing. Just dump everything in the offload buffer
|
||||
void chgBit(uint32_t code, CData newval) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_BIT_0 | newval;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgCData(uint32_t code, CData newval, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_CDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep[2] = newval;
|
||||
m_offloadBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgSData(uint32_t code, SData newval, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_SDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep[2] = newval;
|
||||
m_offloadBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgIData(uint32_t code, IData newval, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_IDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep[2] = newval;
|
||||
m_offloadBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgQData(uint32_t code, QData newval, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_QDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
*reinterpret_cast<QData*>(m_offloadBufferWritep + 2) = newval;
|
||||
m_offloadBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgWData(uint32_t code, const WData* newvalp, int bits) {
|
||||
m_offloadBufferWritep[0] = (bits << 4) | VerilatedTraceOffloadCommand::CHG_WDATA;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_offloadBufferWritep++ = newvalp[i]; }
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgDouble(uint32_t code, double newval) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_DOUBLE;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
*reinterpret_cast<double*>(m_offloadBufferWritep + 2) = newval;
|
||||
m_offloadBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
void chgEvent(uint32_t code, VlEvent newval) {
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT;
|
||||
m_offloadBufferWritep[1] = code;
|
||||
m_offloadBufferWritep += 2;
|
||||
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
|
||||
}
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
||||
+271
-193
@@ -26,10 +26,8 @@
|
||||
|
||||
#include "verilated_intrinsics.h"
|
||||
#include "verilated_trace.h"
|
||||
#ifdef VL_TRACE_PARALLEL
|
||||
# include "verilated_threads.h"
|
||||
# include <list>
|
||||
#endif
|
||||
#include "verilated_threads.h"
|
||||
#include <list>
|
||||
|
||||
#if 0
|
||||
# include <iostream>
|
||||
@@ -43,7 +41,7 @@
|
||||
//=============================================================================
|
||||
// Static utility functions
|
||||
|
||||
static double timescaleToDouble(const char* unitp) {
|
||||
static double timescaleToDouble(const char* unitp) VL_PURE {
|
||||
char* endp = nullptr;
|
||||
double value = std::strtod(unitp, &endp);
|
||||
// On error so we allow just "ns" to return 1e-9.
|
||||
@@ -62,7 +60,7 @@ static double timescaleToDouble(const char* unitp) {
|
||||
return value;
|
||||
}
|
||||
|
||||
static std::string doubleToTimescale(double value) {
|
||||
static std::string doubleToTimescale(double value) VL_PURE {
|
||||
const char* suffixp = "s";
|
||||
// clang-format off
|
||||
if (value >= 1e0) { suffixp = "s"; value *= 1e0; }
|
||||
@@ -78,13 +76,13 @@ static std::string doubleToTimescale(double value) {
|
||||
return valuestr; // Gets converted to string, so no ref to stack
|
||||
}
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
//=========================================================================
|
||||
// Buffer management
|
||||
|
||||
template <> uint32_t* VerilatedTrace<VL_SUB_T, VL_BUF_T>::getOffloadBuffer() {
|
||||
template <>
|
||||
uint32_t* VerilatedTrace<VL_SUB_T, VL_BUF_T>::getOffloadBuffer() {
|
||||
uint32_t* bufferp;
|
||||
// Some jitter is expected, so some number of alternative offlaod buffers are
|
||||
// Some jitter is expected, so some number of alternative offload buffers are
|
||||
// required, but don't allocate more than 8 buffers.
|
||||
if (m_numOffloadBuffers < 8) {
|
||||
// Allocate a new buffer if none is available
|
||||
@@ -101,7 +99,8 @@ template <> uint32_t* VerilatedTrace<VL_SUB_T, VL_BUF_T>::getOffloadBuffer() {
|
||||
return bufferp;
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::waitForOffloadBuffer(const uint32_t* buffp) {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::waitForOffloadBuffer(const uint32_t* buffp) {
|
||||
// Slow path code only called on flush/shutdown, so use a simple algorithm.
|
||||
// Collect buffers from worker and stash them until we get the one we want.
|
||||
std::deque<uint32_t*> stash;
|
||||
@@ -116,7 +115,8 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::waitForOffloadBuffer(const
|
||||
//=========================================================================
|
||||
// Worker thread
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
bool shutdown = false;
|
||||
|
||||
do {
|
||||
@@ -127,7 +127,7 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
|
||||
const uint32_t* readp = bufferp;
|
||||
|
||||
std::unique_ptr<VL_BUF_T> traceBufp; // We own the passed tracebuffer
|
||||
std::unique_ptr<Buffer> traceBufp; // We own the passed tracebuffer
|
||||
|
||||
while (true) {
|
||||
const uint32_t cmd = readp[0];
|
||||
@@ -143,46 +143,50 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
// CHG_* commands
|
||||
case VerilatedTraceOffloadCommand::CHG_BIT_0:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_BIT_0 " << top);
|
||||
traceBufp->chgBitImpl(oldp, 0);
|
||||
traceBufp->chgBit(oldp, 0);
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_BIT_1:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_BIT_1 " << top);
|
||||
traceBufp->chgBitImpl(oldp, 1);
|
||||
traceBufp->chgBit(oldp, 1);
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_CDATA:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_CDATA " << top);
|
||||
// Bits stored in bottom byte of command
|
||||
traceBufp->chgCDataImpl(oldp, *readp, top);
|
||||
traceBufp->chgCData(oldp, *readp, top);
|
||||
readp += 1;
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_SDATA:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_SDATA " << top);
|
||||
// Bits stored in bottom byte of command
|
||||
traceBufp->chgSDataImpl(oldp, *readp, top);
|
||||
traceBufp->chgSData(oldp, *readp, top);
|
||||
readp += 1;
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_IDATA:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_IDATA " << top);
|
||||
// Bits stored in bottom byte of command
|
||||
traceBufp->chgIDataImpl(oldp, *readp, top);
|
||||
traceBufp->chgIData(oldp, *readp, top);
|
||||
readp += 1;
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_QDATA:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_QDATA " << top);
|
||||
// Bits stored in bottom byte of command
|
||||
traceBufp->chgQDataImpl(oldp, *reinterpret_cast<const QData*>(readp), top);
|
||||
traceBufp->chgQData(oldp, *reinterpret_cast<const QData*>(readp), top);
|
||||
readp += 2;
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_WDATA:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_WDATA " << top);
|
||||
traceBufp->chgWDataImpl(oldp, readp, top);
|
||||
traceBufp->chgWData(oldp, readp, top);
|
||||
readp += VL_WORDS_I(top);
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_DOUBLE:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_DOUBLE " << top);
|
||||
traceBufp->chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
|
||||
traceBufp->chgDouble(oldp, *reinterpret_cast<const double*>(readp));
|
||||
readp += 2;
|
||||
continue;
|
||||
case VerilatedTraceOffloadCommand::CHG_EVENT:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
|
||||
traceBufp->chgEvent(oldp, *reinterpret_cast<const VlEvent*>(readp));
|
||||
continue;
|
||||
|
||||
//===
|
||||
// Rare commands
|
||||
@@ -196,7 +200,7 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
case VerilatedTraceOffloadCommand::TRACE_BUFFER:
|
||||
VL_TRACE_OFFLOAD_DEBUG("Command TRACE_BUFFER " << top);
|
||||
readp -= 1; // No code in this command, undo increment
|
||||
traceBufp.reset(*reinterpret_cast<VL_BUF_T* const*>(readp));
|
||||
traceBufp.reset(*reinterpret_cast<Buffer* const*>(readp));
|
||||
readp += 2;
|
||||
continue;
|
||||
|
||||
@@ -231,7 +235,8 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
|
||||
} while (VL_LIKELY(!shutdown));
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::shutdownOffloadWorker() {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::shutdownOffloadWorker() {
|
||||
// If the worker thread is not running, done..
|
||||
if (!m_workerThread) return;
|
||||
|
||||
@@ -246,42 +251,44 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::shutdownOffloadWorker() {
|
||||
m_workerThread.reset(nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// Life cycle
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::closeBase() {
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
shutdownOffloadWorker();
|
||||
while (m_numOffloadBuffers) {
|
||||
delete[] m_offloadBuffersFromWorker.get();
|
||||
--m_numOffloadBuffers;
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::closeBase() {
|
||||
if (offload()) {
|
||||
shutdownOffloadWorker();
|
||||
while (m_numOffloadBuffers) {
|
||||
delete[] m_offloadBuffersFromWorker.get();
|
||||
--m_numOffloadBuffers;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::flushBase() {
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
// Hand an empty buffer to the worker thread
|
||||
uint32_t* const bufferp = getOffloadBuffer();
|
||||
*bufferp = VerilatedTraceOffloadCommand::END;
|
||||
m_offloadBuffersToWorker.put(bufferp);
|
||||
// Wait for it to be returned. As the processing is in-order,
|
||||
// this ensures all previous buffers have been processed.
|
||||
waitForOffloadBuffer(bufferp);
|
||||
#endif
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::flushBase() {
|
||||
if (offload()) {
|
||||
// Hand an empty buffer to the worker thread
|
||||
uint32_t* const bufferp = getOffloadBuffer();
|
||||
*bufferp = VerilatedTraceOffloadCommand::END;
|
||||
m_offloadBuffersToWorker.put(bufferp);
|
||||
// Wait for it to be returned. As the processing is in-order,
|
||||
// this ensures all previous buffers have been processed.
|
||||
waitForOffloadBuffer(bufferp);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Callbacks to run on global events
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::onFlush(void* selfp) {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::onFlush(void* selfp) {
|
||||
// This calls 'flush' on the derived class (which must then get any mutex)
|
||||
reinterpret_cast<VL_SUB_T*>(selfp)->flush();
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::onExit(void* selfp) {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::onExit(void* selfp) {
|
||||
// This calls 'close' on the derived class (which must then get any mutex)
|
||||
reinterpret_cast<VL_SUB_T*>(selfp)->close();
|
||||
}
|
||||
@@ -289,25 +296,26 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::onExit(void* selfp) {
|
||||
//=============================================================================
|
||||
// VerilatedTrace
|
||||
|
||||
template <> VerilatedTrace<VL_SUB_T, VL_BUF_T>::VerilatedTrace() {
|
||||
template <>
|
||||
VerilatedTrace<VL_SUB_T, VL_BUF_T>::VerilatedTrace() {
|
||||
set_time_unit(Verilated::threadContextp()->timeunitString());
|
||||
set_time_resolution(Verilated::threadContextp()->timeprecisionString());
|
||||
}
|
||||
|
||||
template <> VerilatedTrace<VL_SUB_T, VL_BUF_T>::~VerilatedTrace() {
|
||||
template <>
|
||||
VerilatedTrace<VL_SUB_T, VL_BUF_T>::~VerilatedTrace() {
|
||||
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = nullptr);
|
||||
if (m_sigs_enabledp) VL_DO_CLEAR(delete[] m_sigs_enabledp, m_sigs_enabledp = nullptr);
|
||||
Verilated::removeFlushCb(VerilatedTrace<VL_SUB_T, VL_BUF_T>::onFlush, this);
|
||||
Verilated::removeExitCb(VerilatedTrace<VL_SUB_T, VL_BUF_T>::onExit, this);
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
closeBase();
|
||||
#endif
|
||||
if (offload()) closeBase();
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||
// Note: It is possible to re-open a trace file (VCD in particular),
|
||||
// so we must reset the next code here, but it must have the same number
|
||||
// of codes on re-open
|
||||
@@ -340,7 +348,7 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||
// Else if was empty, m_sigs_enabledp = nullptr to short circuit tests
|
||||
// But it isn't, so alloc one bit for each code to indicate enablement
|
||||
// We don't want to still use m_signs_enabledVec as std::vector<bool> is not
|
||||
// guarenteed to be fast
|
||||
// guaranteed to be fast
|
||||
m_sigs_enabledp = new uint32_t[1 + VL_WORDS_I(nextCode())]{0};
|
||||
m_sigs_enabledVec.reserve(nextCode());
|
||||
for (size_t code = 0; code < nextCode(); ++code) {
|
||||
@@ -355,18 +363,18 @@ template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
|
||||
Verilated::addFlushCb(VerilatedTrace<VL_SUB_T, VL_BUF_T>::onFlush, this);
|
||||
Verilated::addExitCb(VerilatedTrace<VL_SUB_T, VL_BUF_T>::onExit, this);
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
// Compute offload buffer size. we need to be able to store a new value for
|
||||
// each signal, which is 'nextCode()' entries after the init callbacks
|
||||
// above have been run, plus up to 2 more words of metadata per signal,
|
||||
// plus fixed overhead of 1 for a termination flag and 3 for a time stamp
|
||||
// update.
|
||||
m_offloadBufferSize = nextCode() + numSignals() * 2 + 4;
|
||||
if (offload()) {
|
||||
// Compute offload buffer size. we need to be able to store a new value for
|
||||
// each signal, which is 'nextCode()' entries after the init callbacks
|
||||
// above have been run, plus up to 2 more words of metadata per signal,
|
||||
// plus fixed overhead of 1 for a termination flag and 3 for a time stamp
|
||||
// update.
|
||||
m_offloadBufferSize = nextCode() + numSignals() * 2 + 4;
|
||||
|
||||
// Start the worker thread
|
||||
m_workerThread.reset(
|
||||
new std::thread{&VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain, this});
|
||||
#endif
|
||||
// Start the worker thread
|
||||
m_workerThread.reset(
|
||||
new std::thread{&VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain, this});
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
@@ -415,14 +423,16 @@ bool VerilatedTrace<VL_SUB_T, VL_BUF_T>::declCode(uint32_t code, const char* nam
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
|
||||
template <> std::string VerilatedTrace<VL_SUB_T, VL_BUF_T>::timeResStr() const {
|
||||
template <>
|
||||
std::string VerilatedTrace<VL_SUB_T, VL_BUF_T>::timeResStr() const {
|
||||
return doubleToTimescale(m_timeRes);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// External interface to client code
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::set_time_unit(const char* unitp) VL_MT_SAFE {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::set_time_unit(const char* unitp) VL_MT_SAFE {
|
||||
m_timeUnit = timescaleToDouble(unitp);
|
||||
}
|
||||
template <>
|
||||
@@ -451,8 +461,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dumpvars(int level, const std::string&
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VL_TRACE_PARALLEL
|
||||
template <> //
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::parallelWorkerTask(void* datap, bool) {
|
||||
ParallelWorkerData* const wdp = reinterpret_cast<ParallelWorkerData*>(datap);
|
||||
// Run the task
|
||||
@@ -463,7 +472,8 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::parallelWorkerTask(void* datap, bool) {
|
||||
if (wdp->m_waiting) wdp->m_cv.notify_one();
|
||||
}
|
||||
|
||||
template <> VL_ATTR_NOINLINE void VerilatedTrace<VL_SUB_T, VL_BUF_T>::ParallelWorkerData::wait() {
|
||||
template <>
|
||||
VL_ATTR_NOINLINE void VerilatedTrace<VL_SUB_T, VL_BUF_T>::ParallelWorkerData::wait() {
|
||||
// Spin for a while, waiting for the buffer to become ready
|
||||
for (int i = 0; i < VL_LOCK_SPINS; ++i) {
|
||||
if (VL_LIKELY(m_ready.load(std::memory_order_relaxed))) return;
|
||||
@@ -475,58 +485,65 @@ template <> VL_ATTR_NOINLINE void VerilatedTrace<VL_SUB_T, VL_BUF_T>::ParallelWo
|
||||
m_cv.wait(lock, [this] { return m_ready.load(std::memory_order_relaxed); });
|
||||
m_waiting = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runParallelCallbacks(const ParallelCallbackMap& cbMap) {
|
||||
for (VlThreadPool* threadPoolp : m_threadPoolps) {
|
||||
#ifdef VL_TRACE_PARALLEL
|
||||
// If tracing in parallel, dispatch to the thread pool (if exists)
|
||||
if (threadPoolp && threadPoolp->numThreads()) {
|
||||
// List of work items for thread (std::list, as ParallelWorkerData is not movable)
|
||||
std::list<ParallelWorkerData> workerData;
|
||||
// We use the whole pool + the main thread
|
||||
const unsigned threads = threadPoolp->numThreads() + 1;
|
||||
// Main thread executes all jobs with index % threads == 0
|
||||
std::vector<ParallelWorkerData*> mainThreadWorkerData;
|
||||
// The tracing callbacks to execute on this thread-pool
|
||||
const auto& cbVec = cbMap.at(threadPoolp);
|
||||
// Enuque all the jobs
|
||||
for (unsigned i = 0; i < cbVec.size(); ++i) {
|
||||
const CallbackRecord& cbr = cbVec[i];
|
||||
// Always get the trace buffer on the main thread
|
||||
Buffer* const bufp = getTraceBuffer();
|
||||
// Create new work item
|
||||
workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp);
|
||||
// Grab the new work item
|
||||
ParallelWorkerData* const itemp = &workerData.back();
|
||||
// Enqueue task to thread pool, or main thread
|
||||
if (unsigned rem = i % threads) {
|
||||
threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp, false);
|
||||
} else {
|
||||
mainThreadWorkerData.push_back(itemp);
|
||||
}
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<CallbackRecord>& cbVec) {
|
||||
if (parallel()) {
|
||||
// If tracing in parallel, dispatch to the thread pool
|
||||
VlThreadPool* threadPoolp = static_cast<VlThreadPool*>(m_contextp->threadPoolp());
|
||||
// List of work items for thread (std::list, as ParallelWorkerData is not movable)
|
||||
std::list<ParallelWorkerData> workerData;
|
||||
// We use the whole pool + the main thread
|
||||
const unsigned threads = threadPoolp->numThreads() + 1;
|
||||
// Main thread executes all jobs with index % threads == 0
|
||||
std::vector<ParallelWorkerData*> mainThreadWorkerData;
|
||||
// Enuque all the jobs
|
||||
for (unsigned i = 0; i < cbVec.size(); ++i) {
|
||||
const CallbackRecord& cbr = cbVec[i];
|
||||
// Always get the trace buffer on the main thread
|
||||
Buffer* const bufp = getTraceBuffer();
|
||||
// Create new work item
|
||||
workerData.emplace_back(cbr.m_dumpCb, cbr.m_userp, bufp);
|
||||
// Grab the new work item
|
||||
ParallelWorkerData* const itemp = &workerData.back();
|
||||
// Enqueue task to thread pool, or main thread
|
||||
if (unsigned rem = i % threads) {
|
||||
threadPoolp->workerp(rem - 1)->addTask(parallelWorkerTask, itemp);
|
||||
} else {
|
||||
mainThreadWorkerData.push_back(itemp);
|
||||
}
|
||||
// Execute main thead jobs
|
||||
for (ParallelWorkerData* const itemp : mainThreadWorkerData) {
|
||||
parallelWorkerTask(itemp, false);
|
||||
}
|
||||
// Commit all trace buffers in order
|
||||
for (ParallelWorkerData& item : workerData) {
|
||||
// Wait until ready
|
||||
item.wait();
|
||||
// Commit the buffer
|
||||
commitTraceBuffer(item.m_bufp);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
// Fall back on sequential execution
|
||||
for (const CallbackRecord& cbr : cbMap.at(threadPoolp)) {
|
||||
Buffer* const traceBufferp = getTraceBuffer();
|
||||
cbr.m_dumpCb(cbr.m_userp, traceBufferp);
|
||||
commitTraceBuffer(traceBufferp);
|
||||
// Execute main thread jobs
|
||||
for (ParallelWorkerData* const itemp : mainThreadWorkerData) {
|
||||
parallelWorkerTask(itemp, false);
|
||||
}
|
||||
// Commit all trace buffers in order
|
||||
for (ParallelWorkerData& item : workerData) {
|
||||
// Wait until ready
|
||||
item.wait();
|
||||
// Commit the buffer
|
||||
commitTraceBuffer(item.m_bufp);
|
||||
}
|
||||
|
||||
// Done
|
||||
return;
|
||||
}
|
||||
// Fall back on sequential execution
|
||||
for (const CallbackRecord& cbr : cbVec) {
|
||||
Buffer* const traceBufferp = getTraceBuffer();
|
||||
cbr.m_dumpCb(cbr.m_userp, traceBufferp);
|
||||
commitTraceBuffer(traceBufferp);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runOffloadedCallbacks(
|
||||
const std::vector<CallbackRecord>& cbVec) {
|
||||
// Fall back on sequential execution
|
||||
for (const CallbackRecord& cbr : cbVec) {
|
||||
Buffer* traceBufferp = getTraceBuffer();
|
||||
cbr.m_dumpOffloadCb(cbr.m_userp, static_cast<OffloadBuffer*>(traceBufferp));
|
||||
commitTraceBuffer(traceBufferp);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -536,13 +553,14 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
|
||||
// This does get the mutex, but if multiple threads are trying to dump
|
||||
// chances are the data being dumped will have other problems
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
if (VL_UNCOVERABLE(m_timeLastDump && timeui <= m_timeLastDump)) { // LCOV_EXCL_START
|
||||
if (VL_UNCOVERABLE(m_didSomeDump && timeui <= m_timeLastDump)) { // LCOV_EXCL_START
|
||||
VL_PRINTF_MT("%%Warning: previous dump at t=%" PRIu64 ", requesting t=%" PRIu64
|
||||
", dump call ignored\n",
|
||||
m_timeLastDump, timeui);
|
||||
return;
|
||||
} // LCOV_EXCL_STOP
|
||||
m_timeLastDump = timeui;
|
||||
m_didSomeDump = true;
|
||||
|
||||
Verilated::quiesce();
|
||||
|
||||
@@ -553,35 +571,43 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
|
||||
if (!preChangeDump()) return;
|
||||
}
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
// Currently only incremental dumps run on the worker thread
|
||||
uint32_t* bufferp = nullptr;
|
||||
if (VL_LIKELY(!m_fullDump)) {
|
||||
// Get the offload buffer we are about to fill
|
||||
bufferp = getOffloadBuffer();
|
||||
m_offloadBufferWritep = bufferp;
|
||||
m_offloadBufferEndp = bufferp + m_offloadBufferSize;
|
||||
if (offload()) {
|
||||
// Currently only incremental dumps run on the worker thread
|
||||
if (VL_LIKELY(!m_fullDump)) {
|
||||
// Get the offload buffer we are about to fill
|
||||
bufferp = getOffloadBuffer();
|
||||
m_offloadBufferWritep = bufferp;
|
||||
m_offloadBufferEndp = bufferp + m_offloadBufferSize;
|
||||
|
||||
// Tell worker to update time point
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::TIME_CHANGE;
|
||||
*reinterpret_cast<uint64_t*>(m_offloadBufferWritep + 1) = timeui;
|
||||
m_offloadBufferWritep += 3;
|
||||
// Tell worker to update time point
|
||||
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::TIME_CHANGE;
|
||||
*reinterpret_cast<uint64_t*>(m_offloadBufferWritep + 1) = timeui;
|
||||
m_offloadBufferWritep += 3;
|
||||
} else {
|
||||
// Update time point
|
||||
flushBase();
|
||||
emitTimeChange(timeui);
|
||||
}
|
||||
} else {
|
||||
// Update time point
|
||||
flushBase();
|
||||
emitTimeChange(timeui);
|
||||
}
|
||||
#else
|
||||
// Update time point
|
||||
emitTimeChange(timeui);
|
||||
#endif
|
||||
|
||||
// Run the callbacks
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
m_fullDump = false; // No more need for next dump to be full
|
||||
runParallelCallbacks(m_fullCbs);
|
||||
if (offload()) {
|
||||
runOffloadedCallbacks(m_fullOffloadCbs);
|
||||
} else {
|
||||
runCallbacks(m_fullCbs);
|
||||
}
|
||||
} else {
|
||||
runParallelCallbacks(m_chgCbs);
|
||||
if (offload()) {
|
||||
runOffloadedCallbacks(m_chgOffloadCbs);
|
||||
} else {
|
||||
runCallbacks(m_chgCbs);
|
||||
}
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
|
||||
@@ -589,76 +615,113 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
|
||||
cbr.m_cleanupCb(cbr.m_userp, self());
|
||||
}
|
||||
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
if (VL_LIKELY(bufferp)) {
|
||||
if (offload() && VL_LIKELY(bufferp)) {
|
||||
// Mark end of the offload buffer we just filled
|
||||
*m_offloadBufferWritep++ = VerilatedTraceOffloadCommand::END;
|
||||
|
||||
// Assert no buffer overflow
|
||||
assert(m_offloadBufferWritep - bufferp <= m_offloadBufferSize);
|
||||
assert(static_cast<size_t>(m_offloadBufferWritep - bufferp) <= m_offloadBufferSize);
|
||||
|
||||
// Reset our pointers as we are giving up the buffer
|
||||
m_offloadBufferWritep = nullptr;
|
||||
m_offloadBufferEndp = nullptr;
|
||||
|
||||
// Pass it to the worker thread
|
||||
m_offloadBuffersToWorker.put(bufferp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Non-hot path internal interface to Verilator generated code
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addThreadPool(VlThreadPool* threadPoolp)
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addModel(VerilatedModel* modelp)
|
||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
for (VlThreadPool* const poolp : m_threadPoolps) {
|
||||
if (poolp == threadPoolp) return;
|
||||
|
||||
const bool firstModel = m_models.empty();
|
||||
const bool newModel = m_models.insert(modelp).second;
|
||||
VerilatedContext* const contextp = modelp->contextp();
|
||||
|
||||
// Validate
|
||||
if (!newModel) { // LCOV_EXCL_START
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"The same model has already been added to this trace file");
|
||||
}
|
||||
m_threadPoolps.push_back(threadPoolp);
|
||||
if (VL_UNCOVERABLE(m_contextp && contextp != m_contextp)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"A trace file instance can only handle models from the same context");
|
||||
}
|
||||
if (VL_UNCOVERABLE(m_didSomeDump)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"Cannot add models to a trace file if 'dump' has already been called");
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
// Keep hold of the context
|
||||
m_contextp = contextp;
|
||||
|
||||
// Get the desired trace config from the model
|
||||
const std::unique_ptr<VerilatedTraceConfig> configp = modelp->traceConfig();
|
||||
|
||||
// Configure trace base class
|
||||
if (!firstModel) {
|
||||
if (m_offload != configp->m_useOffloading) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"Either all or no models using the same trace file must use offloading");
|
||||
}
|
||||
}
|
||||
m_offload = configp->m_useOffloading;
|
||||
// If at least one model requests parallel tracing, then use it
|
||||
m_parallel |= configp->m_useParallel;
|
||||
|
||||
if (VL_UNCOVERABLE(m_parallel && m_offload)) { // LCOV_EXCL_START
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Cannot use parallel tracing with offloading");
|
||||
} // LCOV_EXCL_STOP
|
||||
|
||||
// Configure format specific sub class
|
||||
configure(*(configp.get()));
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
|
||||
CallbackRecord& cbRec)
|
||||
CallbackRecord&& cbRec)
|
||||
VL_MT_SAFE_EXCLUDES(m_mutex) {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
|
||||
const std::string msg = (std::string{"Internal: "} + __FILE__ + "::" + __FUNCTION__
|
||||
+ " called with already open file");
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
} // LCOV_EXCL_STOP
|
||||
cbVec.push_back(cbRec);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addInitCb(initCb_t cb, void* userp) VL_MT_SAFE {
|
||||
CallbackRecord cbr{cb, userp};
|
||||
addCallbackRecord(m_initCbs, cbr);
|
||||
addCallbackRecord(m_initCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, void* userp,
|
||||
VlThreadPool* threadPoolp) VL_MT_SAFE {
|
||||
CallbackRecord cbr{cb, userp};
|
||||
addThreadPool(threadPoolp);
|
||||
addCallbackRecord(m_fullCbs[threadPoolp], cbr);
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_fullCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, void* userp,
|
||||
VlThreadPool* threadPoolp) VL_MT_SAFE {
|
||||
CallbackRecord cbr{cb, userp};
|
||||
addThreadPool(threadPoolp);
|
||||
addCallbackRecord(m_chgCbs[threadPoolp], cbr);
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addFullCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_fullOffloadCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_chgCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addChgCb(dumpOffloadCb_t cb, void* userp) VL_MT_SAFE {
|
||||
addCallbackRecord(m_chgOffloadCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addCleanupCb(cleanupCb_t cb, void* userp) VL_MT_SAFE {
|
||||
CallbackRecord cbr{cb, userp};
|
||||
addCallbackRecord(m_cleanupCbs, cbr);
|
||||
addCallbackRecord(m_cleanupCbs, CallbackRecord{cb, userp});
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::pushNamePrefix(const std::string& prefix) {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::pushNamePrefix(const std::string& prefix) {
|
||||
m_namePrefixStack.push_back(m_namePrefixStack.back() + prefix);
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_SUB_T, VL_BUF_T>::popNamePrefix(unsigned count) {
|
||||
template <>
|
||||
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::popNamePrefix(unsigned count) {
|
||||
while (count--) m_namePrefixStack.pop_back();
|
||||
assert(!m_namePrefixStack.empty());
|
||||
}
|
||||
@@ -756,83 +819,98 @@ static inline void cvtQDataToStr(char* dstp, QData value) {
|
||||
//=========================================================================
|
||||
// VerilatedTraceBuffer
|
||||
|
||||
template <> //
|
||||
VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>::VerilatedTraceBuffer(VL_SUB_T& owner)
|
||||
: m_owner{owner} {
|
||||
#ifdef VL_TRACE_OFFLOAD
|
||||
if (m_offloadBufferWritep) {
|
||||
using This = VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>*;
|
||||
// Tack on the buffer address
|
||||
static_assert(2 * sizeof(uint32_t) >= sizeof(This),
|
||||
"This should be enough on all plafrorms");
|
||||
*m_offloadBufferWritep++ = VerilatedTraceOffloadCommand::TRACE_BUFFER;
|
||||
*reinterpret_cast<This*>(m_offloadBufferWritep) = this;
|
||||
m_offloadBufferWritep += 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
template <>
|
||||
VerilatedTraceBuffer<VL_BUF_T>::VerilatedTraceBuffer(Trace& owner)
|
||||
: VL_BUF_T{owner}
|
||||
, m_sigs_oldvalp{owner.m_sigs_oldvalp}
|
||||
, m_sigs_enabledp{owner.m_sigs_enabledp} {}
|
||||
|
||||
// These functions must write the new value back into the old value store,
|
||||
// and subsequently call the format specific emit* implementations. Note
|
||||
// that this file must be included in the format specific implementation, so
|
||||
// the emit* functions can be inlined for performance.
|
||||
|
||||
template <> //
|
||||
void VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = newval; // Still copy even if not tracing so chg doesn't call full
|
||||
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
|
||||
self()->emitBit(code, newval);
|
||||
emitBit(code, newval);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>::fullCData(uint32_t* oldp, CData newval, int bits) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, VlEvent newval) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = 1; // Do we really store an "event" ?
|
||||
emitEvent(code, newval);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullCData(uint32_t* oldp, CData newval, int bits) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = newval; // Still copy even if not tracing so chg doesn't call full
|
||||
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
|
||||
self()->emitCData(code, newval, bits);
|
||||
emitCData(code, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>::fullSData(uint32_t* oldp, SData newval, int bits) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullSData(uint32_t* oldp, SData newval, int bits) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = newval; // Still copy even if not tracing so chg doesn't call full
|
||||
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
|
||||
self()->emitSData(code, newval, bits);
|
||||
emitSData(code, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>::fullIData(uint32_t* oldp, IData newval, int bits) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullIData(uint32_t* oldp, IData newval, int bits) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*oldp = newval; // Still copy even if not tracing so chg doesn't call full
|
||||
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
|
||||
self()->emitIData(code, newval, bits);
|
||||
emitIData(code, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>::fullQData(uint32_t* oldp, QData newval, int bits) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullQData(uint32_t* oldp, QData newval, int bits) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*reinterpret_cast<QData*>(oldp) = newval;
|
||||
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
|
||||
self()->emitQData(code, newval, bits);
|
||||
emitQData(code, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>::fullWData(uint32_t* oldp, const WData* newvalp,
|
||||
int bits) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullWData(uint32_t* oldp, const WData* newvalp, int bits) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newvalp[i];
|
||||
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
|
||||
self()->emitWData(code, newvalp, bits);
|
||||
emitWData(code, newvalp, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTraceBuffer<VL_SUB_T, VL_BUF_T>::fullDouble(uint32_t* oldp, double newval) {
|
||||
void VerilatedTraceBuffer<VL_BUF_T>::fullDouble(uint32_t* oldp, double newval) {
|
||||
const uint32_t code = oldp - m_sigs_oldvalp;
|
||||
*reinterpret_cast<double*>(oldp) = newval;
|
||||
if (VL_UNLIKELY(m_sigs_enabledp && !(VL_BITISSET_W(m_sigs_enabledp, code)))) return;
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
self()->emitDouble(code, newval);
|
||||
emitDouble(code, newval);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// VerilatedTraceOffloadBuffer
|
||||
|
||||
template <>
|
||||
VerilatedTraceOffloadBuffer<VL_BUF_T>::VerilatedTraceOffloadBuffer(VL_SUB_T& owner)
|
||||
: VerilatedTraceBuffer<VL_BUF_T>{owner}
|
||||
, m_offloadBufferWritep{owner.m_offloadBufferWritep}
|
||||
, m_offloadBufferEndp{owner.m_offloadBufferEndp} {
|
||||
if (m_offloadBufferWritep) {
|
||||
using This = VerilatedTraceBuffer<VL_BUF_T>*;
|
||||
// Tack on the buffer address
|
||||
static_assert(2 * sizeof(uint32_t) >= sizeof(This),
|
||||
"This should be enough on all plafrorms");
|
||||
*m_offloadBufferWritep++ = VerilatedTraceOffloadCommand::TRACE_BUFFER;
|
||||
*reinterpret_cast<This*>(m_offloadBufferWritep) = static_cast<This>(this);
|
||||
m_offloadBufferWritep += 2;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // VL_CPPCHECK
|
||||
|
||||
+403
-52
@@ -29,6 +29,8 @@
|
||||
#endif
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <set>
|
||||
@@ -70,6 +72,72 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
|
||||
#define VL_OUT(name, msb, lsb) IData name ///< Declare output signal, 17-32 bits
|
||||
#define VL_OUTW(name, msb, lsb, words) VlWide<words> name ///< Declare output signal, 65+ bits
|
||||
|
||||
//===================================================================
|
||||
// Activity trigger vector
|
||||
|
||||
template <std::size_t T_size> //
|
||||
class VlTriggerVec final {
|
||||
// TODO: static assert T_size > 0, and don't generate when empty
|
||||
private:
|
||||
// MEMBERS
|
||||
std::array<bool, T_size> m_flags; // State of the assoc array
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
VlTriggerVec() { clear(); }
|
||||
~VlTriggerVec() = default;
|
||||
|
||||
// METHODS
|
||||
|
||||
// Set all elements to false
|
||||
void clear() { m_flags.fill(false); }
|
||||
|
||||
// Reference to element at 'index'
|
||||
bool& at(size_t index) { return m_flags.at(index); }
|
||||
|
||||
// Return true iff at least one element is set
|
||||
bool any() const {
|
||||
for (size_t i = 0; i < m_flags.size(); ++i)
|
||||
if (m_flags[i]) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set all elements true in 'this' that are set in 'other'
|
||||
void set(const VlTriggerVec<T_size>& other) {
|
||||
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] |= other.m_flags[i];
|
||||
}
|
||||
|
||||
// Set elements of 'this' to 'a & !b' element-wise
|
||||
void andNot(const VlTriggerVec<T_size>& a, const VlTriggerVec<T_size>& b) {
|
||||
for (size_t i = 0; i < m_flags.size(); ++i) m_flags[i] = a.m_flags[i] && !b.m_flags[i];
|
||||
}
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// SystemVerilog event type
|
||||
|
||||
class VlEvent final {
|
||||
// MEMBERS
|
||||
bool m_fired = false; // Fired on this scheduling iteration
|
||||
bool m_triggered = false; // Triggered state of event persisting until next time step
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
VlEvent() = default;
|
||||
~VlEvent() = default;
|
||||
|
||||
// METHODS
|
||||
void fire() { m_fired = m_triggered = true; }
|
||||
bool isFired() const { return m_fired; }
|
||||
bool isTriggered() const { return m_triggered; }
|
||||
void clearFired() { m_fired = false; }
|
||||
void clearTriggered() { m_triggered = false; }
|
||||
};
|
||||
|
||||
inline std::string VL_TO_STRING(const VlEvent& e) {
|
||||
return std::string("triggered=") + (e.isTriggered() ? "true" : "false");
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Shuffle RNG
|
||||
|
||||
@@ -91,9 +159,9 @@ class VlReadMem final {
|
||||
const int m_bits; // Bit width of values
|
||||
const std::string& m_filename; // Filename
|
||||
const QData m_end; // End address (as specified by user)
|
||||
FILE* m_fp; // File handle for filename
|
||||
QData m_addr; // Next address to read
|
||||
int m_linenum; // Line number last read from file
|
||||
FILE* m_fp = nullptr; // File handle for filename
|
||||
QData m_addr = 0; // Next address to read
|
||||
int m_linenum = 0; // Line number last read from file
|
||||
bool m_anyAddr = false; // Had address directive in the file
|
||||
public:
|
||||
VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end);
|
||||
@@ -107,8 +175,8 @@ public:
|
||||
class VlWriteMem final {
|
||||
const bool m_hex; // Hex format
|
||||
const int m_bits; // Bit width of values
|
||||
FILE* m_fp; // File handle for filename
|
||||
QData m_addr; // Next address to write
|
||||
FILE* m_fp = nullptr; // File handle for filename
|
||||
QData m_addr = 0; // Next address to write
|
||||
public:
|
||||
VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end);
|
||||
~VlWriteMem();
|
||||
@@ -129,9 +197,10 @@ public:
|
||||
/// zero in memory, but during intermediate operations in the Verilated
|
||||
/// internals is unpredictable.
|
||||
|
||||
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE;
|
||||
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
|
||||
|
||||
template <std::size_t T_Words> struct VlWide final {
|
||||
template <std::size_t T_Words>
|
||||
struct VlWide final {
|
||||
// MEMBERS
|
||||
// This should be the only data member, otherwise generated static initializers need updating
|
||||
EData m_storage[T_Words]; // Contents of the packed array
|
||||
@@ -145,6 +214,12 @@ template <std::size_t T_Words> struct VlWide final {
|
||||
// Default copy assignment operators are used.
|
||||
operator WDataOutP() { return &m_storage[0]; } // This also allows []
|
||||
operator WDataInP() const { return &m_storage[0]; } // This also allows []
|
||||
bool operator!=(const VlWide<T_Words>& that) const {
|
||||
for (size_t i = 0; i < T_Words; ++i) {
|
||||
if (m_storage[i] != that.m_storage[i]) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// METHODS
|
||||
const EData& at(size_t index) const { return m_storage[index]; }
|
||||
@@ -163,7 +238,8 @@ VlWide<T_Words>& VL_CVT_W_A(const WDataInP inp, const VlWide<T_Words>&) {
|
||||
return *((VlWide<T_Words>*)inp);
|
||||
}
|
||||
|
||||
template <std::size_t T_Words> std::string VL_TO_STRING(const VlWide<T_Words>& obj) {
|
||||
template <std::size_t T_Words>
|
||||
std::string VL_TO_STRING(const VlWide<T_Words>& obj) {
|
||||
return VL_TO_STRING_W(T_Words, obj.data());
|
||||
}
|
||||
|
||||
@@ -174,7 +250,8 @@ template <std::size_t T_Words> std::string VL_TO_STRING(const VlWide<T_Words>& o
|
||||
//
|
||||
// Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound
|
||||
// For dynamic arrays it is always zero
|
||||
template <class T_Value, size_t T_MaxSize = 0> class VlQueue final {
|
||||
template <class T_Value, size_t T_MaxSize = 0>
|
||||
class VlQueue final {
|
||||
private:
|
||||
// TYPES
|
||||
using Deque = std::deque<T_Value>;
|
||||
@@ -199,7 +276,8 @@ public:
|
||||
|
||||
// Standard copy constructor works. Verilog: assoca = assocb
|
||||
// Also must allow conversion from a different T_MaxSize queue
|
||||
template <size_t U_MaxSize = 0> VlQueue operator=(const VlQueue<T_Value, U_MaxSize>& rhs) {
|
||||
template <size_t U_MaxSize = 0>
|
||||
VlQueue operator=(const VlQueue<T_Value, U_MaxSize>& rhs) {
|
||||
m_deque = rhs.privateDeque();
|
||||
if (VL_UNLIKELY(T_MaxSize && T_MaxSize < m_deque.size())) m_deque.resize(T_MaxSize - 1);
|
||||
return *this;
|
||||
@@ -289,7 +367,7 @@ public:
|
||||
// Can't just overload operator[] or provide a "at" reference to set,
|
||||
// because we need to be able to insert only when the value is set
|
||||
T_Value& at(int32_t index) {
|
||||
static VL_THREAD_LOCAL T_Value s_throwAway;
|
||||
static thread_local T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||
s_throwAway = atDefault();
|
||||
@@ -300,7 +378,7 @@ public:
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(int32_t index) const {
|
||||
static VL_THREAD_LOCAL T_Value s_throwAway;
|
||||
static thread_local T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
|
||||
return atDefault();
|
||||
@@ -330,18 +408,20 @@ public:
|
||||
|
||||
// Methods
|
||||
void sort() { std::sort(m_deque.begin(), m_deque.end()); }
|
||||
template <typename Func> void sort(Func with_func) {
|
||||
template <typename Func>
|
||||
void sort(Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(m_deque.begin(), m_deque.end(), [=](const T_Value& a, const T_Value& b) {
|
||||
// index number is meaninless with sort, as it changes
|
||||
// index number is meaningless with sort, as it changes
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
}
|
||||
void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); }
|
||||
template <typename Func> void rsort(Func with_func) {
|
||||
template <typename Func>
|
||||
void rsort(Func with_func) {
|
||||
// with_func returns arbitrary type to use for the sort comparison
|
||||
std::sort(m_deque.rbegin(), m_deque.rend(), [=](const T_Value& a, const T_Value& b) {
|
||||
// index number is meaninless with sort, as it changes
|
||||
// index number is meaningless with sort, as it changes
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
}
|
||||
@@ -349,9 +429,9 @@ public:
|
||||
void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG{}); }
|
||||
VlQueue unique() const {
|
||||
VlQueue out;
|
||||
std::unordered_set<T_Value> saw;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
auto it = saw.find(i);
|
||||
const auto it = saw.find(i);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i);
|
||||
out.push_back(i);
|
||||
@@ -359,12 +439,26 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue unique(Func with_func) const {
|
||||
VlQueue out;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
const auto i_mapped = with_func(0, i);
|
||||
const auto it = saw.find(i_mapped);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i_mapped);
|
||||
out.push_back(i);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
VlQueue<IData> unique_index() const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
std::unordered_set<T_Value> saw;
|
||||
std::set<T_Value> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
auto it = saw.find(i);
|
||||
const auto it = saw.find(i);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i);
|
||||
out.push_back(index);
|
||||
@@ -373,7 +467,24 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue find(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<IData> unique_index(Func with_func) const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
std::unordered_set<T_Value> saw;
|
||||
for (const auto& i : m_deque) {
|
||||
const auto i_mapped = with_func(index, i);
|
||||
auto it = saw.find(i_mapped);
|
||||
if (it == saw.end()) {
|
||||
saw.insert(it, i_mapped);
|
||||
out.push_back(index);
|
||||
}
|
||||
++index;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue find(Func with_func) const {
|
||||
VlQueue out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
@@ -382,7 +493,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_index(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<IData> find_index(Func with_func) const {
|
||||
VlQueue<IData> out;
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
@@ -391,7 +503,8 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue find_first(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue find_first(Func with_func) const {
|
||||
// Can't use std::find_if as need index number
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
@@ -400,7 +513,8 @@ public:
|
||||
}
|
||||
return VlQueue{};
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_first_index(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<IData> find_first_index(Func with_func) const {
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) {
|
||||
if (with_func(index, i)) return VlQueue<IData>::cons(index);
|
||||
@@ -408,7 +522,8 @@ public:
|
||||
}
|
||||
return VlQueue<IData>{};
|
||||
}
|
||||
template <typename Func> VlQueue find_last(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue find_last(Func with_func) const {
|
||||
IData index = m_deque.size() - 1;
|
||||
for (auto& item : vlstd::reverse_view(m_deque)) {
|
||||
if (with_func(index, item)) return VlQueue::cons(item);
|
||||
@@ -416,7 +531,8 @@ public:
|
||||
}
|
||||
return VlQueue{};
|
||||
}
|
||||
template <typename Func> VlQueue<IData> find_last_index(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<IData> find_last_index(Func with_func) const {
|
||||
IData index = m_deque.size() - 1;
|
||||
for (auto& item : vlstd::reverse_view(m_deque)) {
|
||||
if (with_func(index, item)) return VlQueue<IData>::cons(index);
|
||||
@@ -431,18 +547,37 @@ public:
|
||||
const auto it = std::min_element(m_deque.begin(), m_deque.end());
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue min(Func with_func) const {
|
||||
if (m_deque.empty()) return VlQueue{};
|
||||
const auto it = std::min_element(m_deque.begin(), m_deque.end(),
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
VlQueue max() const {
|
||||
if (m_deque.empty()) return VlQueue{};
|
||||
const auto it = std::max_element(m_deque.begin(), m_deque.end());
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
template <typename Func>
|
||||
VlQueue max(Func with_func) const {
|
||||
if (m_deque.empty()) return VlQueue{};
|
||||
const auto it = std::max_element(m_deque.begin(), m_deque.end(),
|
||||
[&with_func](const IData& a, const IData& b) {
|
||||
return with_func(0, a) < with_func(0, b);
|
||||
});
|
||||
return VlQueue::cons(*it);
|
||||
}
|
||||
|
||||
T_Value r_sum() const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_deque) out += i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_sum(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out += with_func(index++, i);
|
||||
@@ -456,7 +591,8 @@ public:
|
||||
for (; it != m_deque.end(); ++it) out *= *it;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_product(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_product(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
IData index = 0;
|
||||
@@ -474,7 +610,8 @@ public:
|
||||
for (; it != m_deque.end(); ++it) out &= *it;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_and(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_and(Func with_func) const {
|
||||
if (m_deque.empty()) return T_Value(0);
|
||||
auto it = m_deque.begin();
|
||||
IData index = 0;
|
||||
@@ -489,7 +626,8 @@ public:
|
||||
for (const auto& i : m_deque) out |= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_or(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out |= with_func(index++, i);
|
||||
@@ -500,7 +638,8 @@ public:
|
||||
for (const auto& i : m_deque) out ^= i;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_xor(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
IData index = 0;
|
||||
for (const auto& i : m_deque) out ^= with_func(index++, i);
|
||||
@@ -520,7 +659,8 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
||||
template <class T_Value>
|
||||
std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
||||
return obj.to_string();
|
||||
}
|
||||
|
||||
@@ -529,7 +669,8 @@ template <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& obj) {
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
// be protected by other means
|
||||
//
|
||||
template <class T_Key, class T_Value> class VlAssocArray final {
|
||||
template <class T_Key, class T_Value>
|
||||
class VlAssocArray final {
|
||||
private:
|
||||
// TYPES
|
||||
using Map = std::map<T_Key, T_Value>;
|
||||
@@ -654,19 +795,22 @@ public:
|
||||
}
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find(Func with_func) const {
|
||||
VlQueue<T_Value> out;
|
||||
for (const auto& i : m_map)
|
||||
if (with_func(i.first, i.second)) out.push_back(i.second);
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_index(Func with_func) const {
|
||||
VlQueue<T_Key> out;
|
||||
for (const auto& i : m_map)
|
||||
if (with_func(i.first, i.second)) out.push_back(i.first);
|
||||
return out;
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_first(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
@@ -674,7 +818,8 @@ public:
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_first_index(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
@@ -682,7 +827,8 @@ public:
|
||||
if (it == m_map.end()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Key>::cons(it->first);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<T_Value> find_last(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
@@ -690,7 +836,8 @@ public:
|
||||
if (it == m_map.rend()) return VlQueue<T_Value>{};
|
||||
return VlQueue<T_Value>::cons(it->second);
|
||||
}
|
||||
template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
template <typename Func>
|
||||
VlQueue<T_Key> find_last_index(Func with_func) const {
|
||||
const auto it
|
||||
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
|
||||
return with_func(i.first, i.second);
|
||||
@@ -724,7 +871,8 @@ public:
|
||||
for (const auto& i : m_map) out += i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_sum(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_sum(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out += with_func(i.first, i.second);
|
||||
return out;
|
||||
@@ -737,7 +885,8 @@ public:
|
||||
for (; it != m_map.end(); ++it) out *= it->second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_product(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_product(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{with_func(it->first, it->second)};
|
||||
@@ -753,7 +902,8 @@ public:
|
||||
for (; it != m_map.end(); ++it) out &= it->second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_and(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_and(Func with_func) const {
|
||||
if (m_map.empty()) return T_Value(0);
|
||||
auto it = m_map.begin();
|
||||
T_Value out{with_func(it->first, it->second)};
|
||||
@@ -766,7 +916,8 @@ public:
|
||||
for (const auto& i : m_map) out |= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_or(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_or(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out |= with_func(i.first, i.second);
|
||||
return out;
|
||||
@@ -776,7 +927,8 @@ public:
|
||||
for (const auto& i : m_map) out ^= i.second;
|
||||
return out;
|
||||
}
|
||||
template <typename Func> T_Value r_xor(Func with_func) const {
|
||||
template <typename Func>
|
||||
T_Value r_xor(Func with_func) const {
|
||||
T_Value out(0); // Type must have assignment operator
|
||||
for (const auto& i : m_map) out ^= with_func(i.first, i.second);
|
||||
return out;
|
||||
@@ -839,7 +991,8 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
|
||||
/// This class may get exposed to a Verilated Model's top I/O, if the top
|
||||
/// IO has an unpacked array.
|
||||
|
||||
template <class T_Value, std::size_t T_Depth> struct VlUnpacked final {
|
||||
template <class T_Value, std::size_t T_Depth>
|
||||
struct VlUnpacked final {
|
||||
// MEMBERS
|
||||
// This should be the only data member, otherwise generated static initializers need updating
|
||||
T_Value m_storage[T_Depth]; // Contents of the unpacked array
|
||||
@@ -860,6 +1013,12 @@ template <class T_Value, std::size_t T_Depth> struct VlUnpacked final {
|
||||
T_Value& operator[](size_t index) { return m_storage[index]; }
|
||||
const T_Value& operator[](size_t index) const { return m_storage[index]; }
|
||||
|
||||
// *this != that, which might be used for change detection/trigger computation, but avoid
|
||||
// operator overloading in VlUnpacked for safety in other contexts.
|
||||
bool neq(const VlUnpacked<T_Value, T_Depth>& that) const { return neq(*this, that); }
|
||||
// Similar to 'neq' above, *this = that used for change detection
|
||||
void assign(const VlUnpacked<T_Value, T_Depth>& that) { *this = that; }
|
||||
|
||||
// Dumping. Verilog: str = $sformatf("%p", assoc)
|
||||
std::string to_string() const {
|
||||
std::string out = "'{";
|
||||
@@ -870,6 +1029,22 @@ template <class T_Value, std::size_t T_Depth> struct VlUnpacked final {
|
||||
}
|
||||
return out + "} ";
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T_Val, std::size_t T_Dep>
|
||||
static bool neq(const VlUnpacked<T_Val, T_Dep>& a, const VlUnpacked<T_Val, T_Dep>& b) {
|
||||
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.m_storage[i])) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T_Other> //
|
||||
static bool neq(const T_Other& a, const T_Other& b) {
|
||||
// Base case (T_Other is not VlUnpacked<_, _>), fall back on !=
|
||||
return a != b;
|
||||
}
|
||||
};
|
||||
|
||||
template <class T_Value, std::size_t T_Depth>
|
||||
@@ -877,22 +1052,184 @@ std::string VL_TO_STRING(const VlUnpacked<T_Value, T_Depth>& obj) {
|
||||
return obj.to_string();
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// Object that VlDeleter is capable of deleting
|
||||
|
||||
class VlDeletable VL_NOT_FINAL {
|
||||
public:
|
||||
VlDeletable() = default;
|
||||
virtual ~VlDeletable() = default;
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Class providing delayed deletion of garbage objects. Objects get deleted only when 'deleteAll()'
|
||||
// is called, or the deleter itself is destroyed.
|
||||
|
||||
class VlDeleter final {
|
||||
// MEMBERS
|
||||
// Queue of new objects that should be deleted
|
||||
std::vector<VlDeletable*> m_newGarbage VL_GUARDED_BY(m_mutex);
|
||||
// Queue of objects currently being deleted (only for deleteAll())
|
||||
std::vector<VlDeletable*> m_toDelete VL_GUARDED_BY(m_deleteMutex);
|
||||
mutable VerilatedMutex m_mutex; // Mutex protecting the 'new garbage' queue
|
||||
mutable VerilatedMutex m_deleteMutex; // Mutex protecting the delete queue
|
||||
|
||||
public:
|
||||
// CONSTRUCTOR
|
||||
VlDeleter() = default;
|
||||
~VlDeleter() { deleteAll(); }
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VlDeleter);
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
// Adds a new object to the 'new garbage' queue.
|
||||
void put(VlDeletable* const objp) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock{m_mutex};
|
||||
m_newGarbage.push_back(objp);
|
||||
}
|
||||
|
||||
// Deletes all queued garbage objects.
|
||||
void deleteAll() VL_MT_SAFE;
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Base class for all verilated classes. Includes a reference counter, and a pointer to the deleter
|
||||
// object that should destroy it after the counter reaches 0. This allows for easy construction of
|
||||
// VlClassRefs from 'this'.
|
||||
|
||||
class VlClass VL_NOT_FINAL : public VlDeletable {
|
||||
// TYPES
|
||||
template <typename T_Class>
|
||||
friend class VlClassRef; // Needed for access to the ref counter and deleter
|
||||
|
||||
// MEMBERS
|
||||
std::atomic<size_t> m_counter{0}; // Reference count for this object
|
||||
VlDeleter* m_deleterp = nullptr; // The deleter that will delete this object
|
||||
|
||||
// METHODS
|
||||
// Atomically increments the reference counter
|
||||
void refCountInc() VL_MT_SAFE { ++m_counter; }
|
||||
// Atomically decrements the reference counter. Assuming VlClassRef semantics are sound, it
|
||||
// should never get called at m_counter == 0.
|
||||
void refCountDec() VL_MT_SAFE {
|
||||
if (!--m_counter) m_deleterp->put(this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlClass() = default;
|
||||
VlClass(const VlClass& copied) {}
|
||||
~VlClass() override = default;
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Represents the null pointer. Used for setting VlClassRef to null instead of
|
||||
// via nullptr_t, to prevent the implicit conversion of 0 to nullptr.
|
||||
|
||||
struct VlNull {
|
||||
operator bool() const { return false; }
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Verilog class reference container
|
||||
// There are no multithreaded locks on this; the base variable must
|
||||
// be protected by other means
|
||||
|
||||
#define VlClassRef std::shared_ptr
|
||||
template <typename T_Class>
|
||||
class VlClassRef final {
|
||||
private:
|
||||
// TYPES
|
||||
template <typename T_OtherClass>
|
||||
friend class VlClassRef; // Needed for template copy/move assignments
|
||||
|
||||
template <class T> // T typically of type VlClassRef<x>
|
||||
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
|
||||
if (VL_UNLIKELY(!t)) Verilated::nullPointerError(filename, linenum);
|
||||
return t;
|
||||
}
|
||||
// MEMBERS
|
||||
T_Class* m_objp = nullptr; // Object pointed to
|
||||
|
||||
// METHODS
|
||||
// Increase reference counter with null check
|
||||
void refCountInc() const VL_MT_SAFE {
|
||||
if (m_objp) m_objp->refCountInc();
|
||||
}
|
||||
// Decrease reference counter with null check
|
||||
void refCountDec() const VL_MT_SAFE {
|
||||
if (m_objp) m_objp->refCountDec();
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VlClassRef() = default;
|
||||
// Init with nullptr
|
||||
explicit VlClassRef(VlNull){};
|
||||
template <typename... T_Args>
|
||||
VlClassRef(VlDeleter& deleter, T_Args&&... args)
|
||||
: m_objp{new T_Class{std::forward<T_Args>(args)...}} {
|
||||
m_objp->m_deleterp = &deleter;
|
||||
refCountInc();
|
||||
}
|
||||
// Explicit to avoid implicit conversion from 0
|
||||
explicit VlClassRef(T_Class* objp)
|
||||
: m_objp{objp} {
|
||||
refCountInc();
|
||||
}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VlClassRef(const VlClassRef& copied)
|
||||
: m_objp{copied.m_objp} {
|
||||
refCountInc();
|
||||
}
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VlClassRef(VlClassRef&& moved)
|
||||
: m_objp{vlstd::exchange(moved.m_objp, nullptr)} {}
|
||||
~VlClassRef() { refCountDec(); }
|
||||
|
||||
// METHODS
|
||||
// Copy and move assignments
|
||||
VlClassRef& operator=(const VlClassRef& copied) {
|
||||
refCountDec();
|
||||
m_objp = copied.m_objp;
|
||||
refCountInc();
|
||||
return *this;
|
||||
}
|
||||
VlClassRef& operator=(VlClassRef&& moved) {
|
||||
refCountDec();
|
||||
m_objp = vlstd::exchange(moved.m_objp, nullptr);
|
||||
return *this;
|
||||
}
|
||||
template <typename T_OtherClass>
|
||||
VlClassRef& operator=(const VlClassRef<T_OtherClass>& copied) {
|
||||
refCountDec();
|
||||
m_objp = copied.m_objp;
|
||||
refCountInc();
|
||||
return *this;
|
||||
}
|
||||
template <typename T_OtherClass>
|
||||
VlClassRef& operator=(VlClassRef<T_OtherClass>&& moved) {
|
||||
refCountDec();
|
||||
m_objp = vlstd::exchange(moved.m_objp, nullptr);
|
||||
return *this;
|
||||
}
|
||||
// Assign with nullptr
|
||||
VlClassRef& operator=(VlNull) {
|
||||
refCountDec();
|
||||
m_objp = nullptr;
|
||||
return *this;
|
||||
}
|
||||
// Dynamic caster
|
||||
template <typename T_OtherClass>
|
||||
VlClassRef<T_OtherClass> dynamicCast() const {
|
||||
return VlClassRef<T_OtherClass>{dynamic_cast<T_OtherClass*>(m_objp)};
|
||||
}
|
||||
// Dereference operators
|
||||
T_Class& operator*() const { return *m_objp; }
|
||||
T_Class* operator->() const { return m_objp; }
|
||||
// For 'if (ptr)...'
|
||||
operator bool() const { return m_objp; }
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
|
||||
VlClassRef<U> casted = std::dynamic_pointer_cast<U>(in);
|
||||
VlClassRef<U> casted = in.template dynamicCast<U>();
|
||||
if (VL_LIKELY(casted)) {
|
||||
outr = casted;
|
||||
return true;
|
||||
@@ -903,4 +1240,18 @@ static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
|
||||
|
||||
//======================================================================
|
||||
|
||||
#define VL_NEW(Class, ...) \
|
||||
VlClassRef<Class> { vlSymsp->__Vm_deleter, __VA_ARGS__ }
|
||||
|
||||
#define VL_KEEP_THIS \
|
||||
VlClassRef<std::remove_pointer<decltype(this)>::type> __Vthisref { this }
|
||||
|
||||
template <class T> // T typically of type VlClassRef<x>
|
||||
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
|
||||
if (VL_UNLIKELY(!t)) Verilated::nullPointerError(filename, linenum);
|
||||
return t;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
#endif // Guard
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user