mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
77553d23fc | ||
|
|
3b9c8b64f7 | ||
|
|
7e5f562500 | ||
|
|
d4d3ae4dfc | ||
|
|
79b1b07fcd | ||
|
|
e3cf5c07e4 | ||
|
|
8750352495 | ||
|
|
3d8dc2774b | ||
|
|
0a9ae154be | ||
|
|
e25a6334cf | ||
|
|
070bead9f9 | ||
|
|
549921be2e | ||
|
|
7c05033b79 | ||
|
|
215d3614c0 | ||
|
|
1ebf937a6c | ||
|
|
7be343fd7c | ||
|
|
fb2d78520f | ||
|
|
c5da072ff6 | ||
|
|
efbcb094ca | ||
|
|
5033c906fd | ||
|
|
f8ab30d127 | ||
|
|
222ca4b009 | ||
|
|
e3a1954e20 | ||
|
|
4ba2637360 | ||
|
|
6430743b6f | ||
|
|
0c49cca527 | ||
|
|
7a9e79ea79 | ||
|
|
157948c552 | ||
|
|
1a127a479c | ||
|
|
87e4a86fbb | ||
|
|
1c1b95161b | ||
|
|
66d1754d19 | ||
|
|
57a53c014d | ||
|
|
e48a859b86 | ||
|
|
430238a6b4 | ||
|
|
9a4c5509fc | ||
|
|
0765443353 | ||
|
|
d07a6f81e4 | ||
|
|
fac04521db | ||
|
|
d0819f156f | ||
|
|
b77eab3f83 | ||
|
|
30f3774134 | ||
|
|
1899a875a4 | ||
|
|
cc134b38ee | ||
|
|
993115d30a | ||
|
|
c1d35c8622 | ||
|
|
16fba59480 | ||
|
|
4266c789ce | ||
|
|
627d83e807 | ||
|
|
80f5738544 | ||
|
|
600641b4a1 | ||
|
|
70eb99b050 | ||
|
|
dc1ad16b03 | ||
|
|
ba5779c69e | ||
|
|
069eb97eca | ||
|
|
96a959154a | ||
|
|
4f88ec3518 | ||
|
|
ef4f91ae5a | ||
|
|
45eccaecaf | ||
|
|
0397e19726 | ||
|
|
687edba969 | ||
|
|
02e83da2fa | ||
|
|
ef04ada12b | ||
|
|
bed3101dfc | ||
|
|
4265f9499d | ||
|
|
6acd5847e7 | ||
|
|
16547077a1 | ||
|
|
3ad3944f2c | ||
|
|
be8f1a25c6 | ||
|
|
f7f3d3fd43 | ||
|
|
4003e01283 | ||
|
|
917d3b0fb3 | ||
|
|
3d073c9534 | ||
|
|
20206b1e2e | ||
|
|
fefe731105 | ||
|
|
1dce6b2500 | ||
|
|
d2fac4aa2f | ||
|
|
132cc1d068 | ||
|
|
f4a72946eb | ||
|
|
e10156548d | ||
|
|
4e6d2cfe38 | ||
|
|
7f3a73e314 | ||
|
|
143050e034 | ||
|
|
8455ee7091 | ||
|
|
9702d11657 | ||
|
|
decbf79f39 | ||
|
|
2d7d2c5992 | ||
|
|
2abbd5c145 | ||
|
|
583605b218 | ||
|
|
67fab0b4fc | ||
|
|
43213fcdc2 | ||
|
|
f632ea500c | ||
|
|
dbb69412e5 | ||
|
|
d7bc0ff5e5 | ||
|
|
14604a24d6 | ||
|
|
816c5e0dc9 | ||
|
|
aa39d020d8 | ||
|
|
b67f1f0e94 | ||
|
|
f5546febe8 | ||
|
|
27181d534e | ||
|
|
698e0fbbd1 | ||
|
|
ea9b65fe6d | ||
|
|
3c1ed075e5 | ||
|
|
6013b54f7b | ||
|
|
d75a8624c1 | ||
|
|
ac04e85a1c | ||
|
|
78aee6f4e7 | ||
|
|
ee9d6dd63f | ||
|
|
034737d2a8 | ||
|
|
72d2cff0a1 | ||
|
|
033e7ac020 | ||
|
|
042d3eed23 | ||
|
|
ea4031cbd3 | ||
|
|
c0127599df | ||
|
|
7c54a451a9 | ||
|
|
2118038cb9 | ||
|
|
9927e8b3ee | ||
|
|
953a442827 | ||
|
|
f3b28c5c74 | ||
|
|
7a33fe2bf2 | ||
|
|
bdecf6c4e1 | ||
|
|
6fcf05e2b6 | ||
|
|
4a5e4b04f3 | ||
|
|
5d98035170 | ||
|
|
20c906261b | ||
|
|
74754d94c3 | ||
|
|
98cd925fda | ||
|
|
e029ba845e | ||
|
|
e53a522662 | ||
|
|
2bc813da4a | ||
|
|
555408b5d3 | ||
|
|
a07f2b3611 | ||
|
|
c85589371a | ||
|
|
1280070abb | ||
|
|
a52f975bd7 | ||
|
|
0c70f0c786 | ||
|
|
edf6a40f19 | ||
|
|
58739a0a99 | ||
|
|
1488f9130d | ||
|
|
a18d8cbe86 | ||
|
|
bfea4b7f99 | ||
|
|
84b8307938 | ||
|
|
ce340658d6 | ||
|
|
a02c420064 | ||
|
|
d55c233427 | ||
|
|
25bbbbd37b | ||
|
|
fdb4d3a145 | ||
|
|
ced1af8cb8 | ||
|
|
f0a6e4c2b2 | ||
|
|
9e5cd463e5 | ||
|
|
bb8899f307 | ||
|
|
1194dbf19c | ||
|
|
0cd4a57ad9 | ||
|
|
1bd1e21a69 | ||
|
|
7e7447812c | ||
|
|
af3ab13012 | ||
|
|
b35b5aacfa | ||
|
|
9c01665078 | ||
|
|
a500140f1d | ||
|
|
dced49a804 | ||
|
|
f8a67b2fe8 | ||
|
|
8cdecd5668 | ||
|
|
75d255a3bf | ||
|
|
0674267333 | ||
|
|
1632160fb1 | ||
|
|
e609328ebb | ||
|
|
8291ef6537 | ||
|
|
30600bf1a3 | ||
|
|
b968f57711 | ||
|
|
ee7b399bf5 | ||
|
|
50c28fa9d3 | ||
|
|
a17f51eac0 | ||
|
|
cc50126ad3 | ||
|
|
9d1a39a5e4 | ||
|
|
82cc1a319f | ||
|
|
2fd23458ce | ||
|
|
271fa5fe3c | ||
|
|
04c96694e6 | ||
|
|
e7bd44561c | ||
|
|
4d5e448664 | ||
|
|
236c2141e3 | ||
|
|
788fe3dc27 | ||
|
|
a2abd361db | ||
|
|
09806d7576 | ||
|
|
a2aa678278 | ||
|
|
0b09636c58 | ||
|
|
af197f2ceb | ||
|
|
748c818ccb | ||
|
|
ad55564905 | ||
|
|
ad2cb45a14 | ||
|
|
277fd9197f | ||
|
|
61ff7039b4 | ||
|
|
7342cf278a | ||
|
|
958654909f | ||
|
|
d9be86d69a | ||
|
|
378d947702 | ||
|
|
98b5417e04 | ||
|
|
0af971292e | ||
|
|
43a2fa080a | ||
|
|
0cdc2e038c | ||
|
|
d4a411db6c | ||
|
|
8d367dc8a3 | ||
|
|
5a4cc333fb | ||
|
|
f13fd4478c | ||
|
|
23e4a0f784 | ||
|
|
aa595d40de | ||
|
|
fa828ac9ba | ||
|
|
b1495f0742 | ||
|
|
8006b5479c | ||
|
|
19c2906a64 | ||
|
|
c367b671b6 | ||
|
|
35226d5e1a | ||
|
|
fac89c5d62 | ||
|
|
f40f0464e2 | ||
|
|
262ed9c03a | ||
|
|
a7edf13d62 | ||
|
|
6e57076726 | ||
|
|
cef56c6fca | ||
|
|
91f30af01f | ||
|
|
3c8953fec2 | ||
|
|
6de78d58fa | ||
|
|
d42f9c095b | ||
|
|
46e10173f8 | ||
|
|
d84c7df38f | ||
|
|
6e2d8df9e5 | ||
|
|
e2b40195b4 | ||
|
|
541f983dba | ||
|
|
5658cd3394 | ||
|
|
3963a50aef | ||
|
|
47f040a5fd | ||
|
|
7b7a2e99e3 | ||
|
|
25397e7612 | ||
|
|
4984d19ae9 | ||
|
|
305448ea86 | ||
|
|
4a1d18f0e9 | ||
|
|
30482f3eea | ||
|
|
b469feb44b | ||
|
|
466fd56d18 | ||
|
|
1aaf3f3424 | ||
|
|
b5e4917405 | ||
|
|
140671300c | ||
|
|
820a4dbbdd | ||
|
|
53d8ccd149 | ||
|
|
418b36ea71 | ||
|
|
05e51d0d18 | ||
|
|
575c565e77 | ||
|
|
01255082a6 | ||
|
|
0098e67e59 | ||
|
|
3798a472b5 | ||
|
|
0e322e2e85 | ||
|
|
5cd5c05c05 | ||
|
|
933e796cc2 | ||
|
|
ae701e014d | ||
|
|
3a0b8c8870 | ||
|
|
dea0e6793f | ||
|
|
4862916f39 | ||
|
|
870ec27b73 | ||
|
|
a21947d887 | ||
|
|
893dee3434 | ||
|
|
f083805ab5 | ||
|
|
7067afde5d | ||
|
|
1eaec2aa8a | ||
|
|
da01810d98 | ||
|
|
4c7d5a1dc0 | ||
|
|
d15e3d93c4 | ||
|
|
aae2bf872c | ||
|
|
04c0fc8aa7 | ||
|
|
1d8955fea5 | ||
|
|
48740a0dba | ||
|
|
4a404bd92e | ||
|
|
ff41701ddc | ||
|
|
2590c9c4a6 | ||
|
|
c5d61da5d2 | ||
|
|
5a622fd9db | ||
|
|
c83b1478e1 | ||
|
|
3243651c63 | ||
|
|
8d61cd9029 | ||
|
|
7fe49de420 | ||
|
|
a433096d5a | ||
|
|
b88e1e6970 | ||
|
|
79f228b04f | ||
|
|
d7cc1e6844 | ||
|
|
42312101b5 | ||
|
|
329f5b712a | ||
|
|
6ddd92c0a1 | ||
|
|
277dee109c | ||
|
|
ef71576825 | ||
|
|
c3271aa891 | ||
|
|
1cf17b5e78 | ||
|
|
2b6353b36e | ||
|
|
8b647f0977 | ||
|
|
4c31c5fab5 | ||
|
|
6ce878cb0d | ||
|
|
a67ba04c37 | ||
|
|
ae448e5ef9 | ||
|
|
a57826b125 | ||
|
|
656c460605 | ||
|
|
95534fa5c5 | ||
|
|
611e8b10c6 | ||
|
|
047852eb08 | ||
|
|
6318a08056 | ||
|
|
b60a92eed3 | ||
|
|
fe306a36b8 | ||
|
|
18870f8b62 | ||
|
|
9712ceedd7 | ||
|
|
2e32387e5c | ||
|
|
b66877c9df | ||
|
|
74a6f94e2b | ||
|
|
35fc8b7259 | ||
|
|
e591afd101 | ||
|
|
a41cdf4cfb | ||
|
|
ef72c42aa7 | ||
|
|
fbc814b54a | ||
|
|
4cfa3f879a | ||
|
|
4a8c7e869f | ||
|
|
a4a1c7a384 | ||
|
|
460315128b | ||
|
|
8ddafb4d9f | ||
|
|
ebda8f866c | ||
|
|
5ee4595aa8 | ||
|
|
5089ac6119 | ||
|
|
3f66f846cd | ||
|
|
279f21bb5b | ||
|
|
773ed97504 | ||
|
|
b6d4899d3f | ||
|
|
9d48ff7745 | ||
|
|
c4aab57c62 | ||
|
|
e8f27be200 | ||
|
|
15f0f967b3 | ||
|
|
cbafff8a71 | ||
|
|
41e362b580 | ||
|
|
622f59ad65 | ||
|
|
c5da38206e | ||
|
|
d737266f64 | ||
|
|
978c35995a | ||
|
|
2af7f2fa18 | ||
|
|
373c9090d3 | ||
|
|
723d407a87 | ||
|
|
dc90e6c3c3 | ||
|
|
68a2ed6776 | ||
|
|
7f32d4dc45 | ||
|
|
7b683fe258 | ||
|
|
72858175a2 | ||
|
|
9d7086067c | ||
|
|
5bb1da88ed | ||
|
|
9969a60b34 | ||
|
|
72402fa91e | ||
|
|
8255f3f9fe | ||
|
|
8957f77793 | ||
|
|
7187b82d1d | ||
|
|
1a92a58720 | ||
|
|
2351f9b9ad | ||
|
|
abc3c216f8 | ||
|
|
f1afa667d7 | ||
|
|
76d0671952 | ||
|
|
424769c32b | ||
|
|
f7249ad23a | ||
|
|
613d76c578 | ||
|
|
50662751fe | ||
|
|
c9e59e767a | ||
|
|
a7432bdea7 | ||
|
|
9ffad7f0db | ||
|
|
3097d5e093 | ||
|
|
cff4b5a5ee | ||
|
|
eda46e3949 | ||
|
|
71651718d4 | ||
|
|
da0cb44954 | ||
|
|
57621a93ad | ||
|
|
6a882f9dc6 | ||
|
|
c18b0eb122 | ||
|
|
3c28a66acf | ||
|
|
5c11de1663 | ||
|
|
72ea6bf414 | ||
|
|
101314a572 | ||
|
|
01f3e81a36 | ||
|
|
3cb3b6c400 | ||
|
|
8f58b58853 | ||
|
|
b66826169d | ||
|
|
d2a7376f14 | ||
|
|
c9e8a1cb4d | ||
|
|
8170f6f03f | ||
|
|
0abf88823f | ||
|
|
accf5a9a17 | ||
|
|
c64c81b7a3 | ||
|
|
7834028842 | ||
|
|
1e0d5eb238 | ||
|
|
b5460bd867 | ||
|
|
53cde90c8f | ||
|
|
d20a4db773 | ||
|
|
0f7677480f | ||
|
|
ba3930777a | ||
|
|
9c054a5774 | ||
|
|
cef0105dfc | ||
|
|
4773a1e77c | ||
|
|
ed4c7038b4 | ||
|
|
c4f31d3bb6 | ||
|
|
dc25e9b949 | ||
|
|
1f52b01b2c | ||
|
|
d5fc0fca41 | ||
|
|
212aa332dd | ||
|
|
17e7da77f0 | ||
|
|
201f0d3f5f | ||
|
|
7d0b3b300a | ||
|
|
0b55e205f7 | ||
|
|
9c0c6439cc | ||
|
|
d33d0301f8 | ||
|
|
6fd7f45cef | ||
|
|
57a937df03 | ||
|
|
ffd461dcf8 | ||
|
|
f77058774e | ||
|
|
1d0a726437 | ||
|
|
29bcbb0417 | ||
|
|
2d11c2cbb3 | ||
|
|
2edbcce032 | ||
|
|
35a53d9adb | ||
|
|
2885c2ce97 | ||
|
|
900c023bb5 | ||
|
|
12b95f6b93 | ||
|
|
85de3048a5 | ||
|
|
c1a9fe07e9 | ||
|
|
1a0da2e4ec | ||
|
|
38d11ecabe | ||
|
|
148762364b | ||
|
|
68d7596adf | ||
|
|
f005b7fd87 | ||
|
|
68ed683681 | ||
|
|
61e41595a2 | ||
|
|
484b574cef | ||
|
|
29695adf70 | ||
|
|
fac43811fd | ||
|
|
15f63d12d5 | ||
|
|
ba7b3fd60f | ||
|
|
897b9ccfe2 | ||
|
|
b97e1aa9fe | ||
|
|
d4a631446b | ||
|
|
a2cc053c6f | ||
|
|
8998ffc4e5 | ||
|
|
ca162716c6 | ||
|
|
629dd16714 | ||
|
|
12b903caf4 | ||
|
|
f9a0cf0cff | ||
|
|
070bcddf5a | ||
|
|
feb1e2bd48 | ||
|
|
6e7ee23644 | ||
|
|
c00cc18d37 | ||
|
|
a7e17a8855 | ||
|
|
60fa1db731 | ||
|
|
ac09ad3ffd | ||
|
|
27953e26b6 | ||
|
|
9375d9f603 | ||
|
|
72bd91c7f1 | ||
|
|
8850ca962e | ||
|
|
7fd590f855 | ||
|
|
5f7ae1fbce | ||
|
|
b56a25e89c | ||
|
|
4f32b093e6 | ||
|
|
6a54fb6f96 | ||
|
|
546ccd56c4 | ||
|
|
ca77a93214 | ||
|
|
ee1b20e1cd | ||
|
|
aa86e0bbc0 | ||
|
|
b6b3482010 | ||
|
|
05aecd2c0b | ||
|
|
6ab3d8f3ed | ||
|
|
0fcc7f2987 | ||
|
|
7d7e67b49b | ||
|
|
a41ea180fa | ||
|
|
98889b3f4e | ||
|
|
83fbfa8c71 | ||
|
|
a57262d6e7 | ||
|
|
fe708f045a | ||
|
|
8afcd67a1f | ||
|
|
16e258eb4c | ||
|
|
d6fbbddac9 | ||
|
|
9dc65df982 | ||
|
|
8f64e4a76f | ||
|
|
6e9008fb5a | ||
|
|
5ded80cf79 | ||
|
|
a6deee2083 | ||
|
|
e1f45dd84a | ||
|
|
9fd4541069 | ||
|
|
849487da23 | ||
|
|
dc64b43152 | ||
|
|
209a585a68 | ||
|
|
aa9cde22c8 | ||
|
|
faf7255e83 | ||
|
|
a6c97cc3bc | ||
|
|
977ceb404d | ||
|
|
b44efe7ef7 | ||
|
|
15ad3f46be | ||
|
|
c6d1a9858a | ||
|
|
77cc335c2d | ||
|
|
a95eb53684 | ||
|
|
910803e6db | ||
|
|
dd967f7769 | ||
|
|
b79ef672e1 | ||
|
|
70549e1a64 | ||
|
|
87e1c36e4a | ||
|
|
9991b19610 | ||
|
|
1381d3dbde | ||
|
|
5e575f5906 | ||
|
|
e2cbcd37d8 | ||
|
|
3b37b5b92d | ||
|
|
10b4678ee6 | ||
|
|
c1665818b9 | ||
|
|
27f4399c31 | ||
|
|
df52e481fb | ||
|
|
f93ae707e0 | ||
|
|
6ed10b7fde | ||
|
|
8208fe8a0e | ||
|
|
ace35b3e81 | ||
|
|
2b58e834ee | ||
|
|
14643643c9 | ||
|
|
7176aee852 | ||
|
|
c96a43b452 | ||
|
|
77915f78db | ||
|
|
c52f3349d1 | ||
|
|
6ab51de96d | ||
|
|
97cbc10925 | ||
|
|
65cd4f6047 | ||
|
|
174fd1bf0e | ||
|
|
b12413e42f | ||
|
|
7709130d93 | ||
|
|
15f7685755 | ||
|
|
83c6e9e821 | ||
|
|
1cacb1deab | ||
|
|
03bc8b7480 | ||
|
|
7d6668a3bd | ||
|
|
def40fab9b | ||
|
|
fceedd9f4d | ||
|
|
4272f2116e | ||
|
|
39d903375b | ||
|
|
9164eb03d5 | ||
|
|
7b789fe02a | ||
|
|
4ae3d3af71 | ||
|
|
6a54922044 | ||
|
|
466535abdc | ||
|
|
efacac2e3d | ||
|
|
74e16d85c5 | ||
|
|
39d7cbf412 | ||
|
|
8f7e463656 | ||
|
|
e6f345e45d | ||
|
|
d4f7f5297a | ||
|
|
9b8aebb00c | ||
|
|
58091edd68 | ||
|
|
18412f9322 | ||
|
|
1883ab29cb | ||
|
|
1a64c7d232 | ||
|
|
f3308d236b | ||
|
|
1b94e3b0e2 | ||
|
|
08b74e5ab9 | ||
|
|
5c966ec510 | ||
|
|
dc5c259069 | ||
|
|
dc27a179e2 | ||
|
|
236e6baa76 | ||
|
|
dba88bae3c | ||
|
|
d4b6e2b2b5 | ||
|
|
1e2d73fc80 | ||
|
|
ea3acc2d3a | ||
|
|
152505e879 | ||
|
|
8e6674066f | ||
|
|
8b2666cd04 | ||
|
|
afa8e4c786 | ||
|
|
ef211fc9e0 | ||
|
|
1a6c2fc55d | ||
|
|
15b40a97d9 | ||
|
|
343db78c03 | ||
|
|
4c1ae4701a | ||
|
|
05f213c266 | ||
|
|
0f617988d4 | ||
|
|
1e0b37f4bc | ||
|
|
991d8b178b | ||
|
|
608d5a87d1 | ||
|
|
914a6edd33 | ||
|
|
0cfa828572 | ||
|
|
4556b6c022 | ||
|
|
cba05480ba | ||
|
|
2abbae8dd0 | ||
|
|
f13bd1aec4 | ||
|
|
b6c21ad21a | ||
|
|
26301a4133 | ||
|
|
383f9832d4 | ||
|
|
50535a1894 | ||
|
|
ff31abe341 | ||
|
|
763f621d4c | ||
|
|
d922cae0a2 | ||
|
|
efaf375887 | ||
|
|
5932eae32a | ||
|
|
a331397954 | ||
|
|
a494ad5ec7 | ||
|
|
b617cd5549 | ||
|
|
e55338f927 | ||
|
|
6eadb8e771 | ||
|
|
f6048cc9c1 | ||
|
|
9fdb026e95 | ||
|
|
bf17bb4648 | ||
|
|
4dc1f40856 | ||
|
|
5302a9d0e6 | ||
|
|
e07e9390f6 | ||
|
|
a13eab55f5 | ||
|
|
b2228afd1a |
+2
-2
@@ -13,7 +13,7 @@ AllowShortBlocksOnASingleLine: true
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortIfStatementsOnASingleLine: true
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
@@ -104,7 +104,7 @@ SpacesInContainerLiterals: true
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp03
|
||||
Standard: Cpp11
|
||||
TabWidth: 8
|
||||
UseTab: Never
|
||||
...
|
||||
|
||||
@@ -3,3 +3,4 @@ exclude_paths:
|
||||
- '.github/**'
|
||||
- 'ci/build_verilator.sh'
|
||||
- 'include/vltstd/**'
|
||||
- 'nodist/fastcov.py'
|
||||
|
||||
@@ -11,4 +11,6 @@ Thanks for taking the time to report this.
|
||||
|
||||
Can you attach an example that shows the issue? (Must be openly licensed, ideally in test_regress format.)
|
||||
|
||||
May we assist you in trying to fix this yourself?
|
||||
What 'verilator --version' are you using? Did you try it with the git master version?
|
||||
|
||||
Would you be willing to try to fix Verilator yourself with assistance?
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
\#*
|
||||
.#*
|
||||
.nfs*
|
||||
*~
|
||||
*.tidy
|
||||
*.old
|
||||
|
||||
+122
-160
@@ -8,176 +8,138 @@
|
||||
|
||||
version: ~> 1.0
|
||||
|
||||
os: linux
|
||||
language: cpp
|
||||
cache: ccache
|
||||
|
||||
env:
|
||||
global:
|
||||
- VERILATOR_CACHE=$HOME/verilator_cache
|
||||
- VERILATOR_ROOT=$PWD
|
||||
- VERILATOR_NUM_JOBS=$(echo `nproc` + 1 | bc)
|
||||
- VERILATOR_CONFIG_FLAGS="--enable-maintainer-mode --enable-longtests"
|
||||
- VERILATOR_AUTHOR_SITE=1
|
||||
- OBJCACHE=ccache
|
||||
|
||||
cache:
|
||||
directories:
|
||||
- $VERILATOR_CACHE
|
||||
- $HOME/.ccache
|
||||
|
||||
before_install:
|
||||
# Perl modules needed for testing
|
||||
# Not listing Bit::Vector as slow to install, and only skips one test
|
||||
- yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
||||
- sudo apt-get install gdb gtkwave
|
||||
- sudo apt-get install libgoogle-perftools-dev
|
||||
before_script:
|
||||
- bash -x ci/build_vcddiff.sh
|
||||
- bash -x ci/build_verilator.sh
|
||||
after_script:
|
||||
- ccache -s
|
||||
env:
|
||||
global:
|
||||
- VERILATOR_ROOT=$TRAVIS_BUILD_DIR
|
||||
|
||||
# The list and order of build stages
|
||||
stages:
|
||||
- "Build Verilator"
|
||||
- test
|
||||
- build # Build Verilator
|
||||
- test # Run tests
|
||||
|
||||
# Dump info about the environment for debugging
|
||||
before_install:
|
||||
# To dump the script that Travis itself is executing, add 'cat $0' here
|
||||
- cd "$TRAVIS_BUILD_DIR" # Skipping the git clone in later stages requires this
|
||||
- export CCACHE_MAXSIZE=$(ci/travis-ccache-size.bash) # Set here after the 'cd'
|
||||
- env | sort
|
||||
- ls -lA .
|
||||
- ls -lA bin
|
||||
- g++ -E -dM -c -x c++ /dev/null | sort
|
||||
- clang++ -E -dM -c -x c++ /dev/null | sort
|
||||
|
||||
# Install all dependencies
|
||||
# We run twice to attempt on failure to recover from temp network problems
|
||||
install:
|
||||
- ./ci/travis-install.bash || ./ci/travis-install.bash
|
||||
|
||||
before_script:
|
||||
# ccache maintenance
|
||||
- ./ci/travis-ccache-maint.bash
|
||||
# Don't produce core dumps (esp. on FreeBSD)
|
||||
- ulimit -c 0
|
||||
# On Focal, set the SystemC installation location
|
||||
- |
|
||||
if [ "$TRAVIS_DIST" = "focal" ] && [ "$M32" != "1" ]; then
|
||||
export SYSTEMC_INCLUDE=/usr/include
|
||||
export SYSTEMC_LIBDIR=/usr/lib/x86_64-linux-gnu
|
||||
fi
|
||||
# Override compiler for M32
|
||||
- |
|
||||
if [ "$M32" = "1" ]; then
|
||||
export CC="$CC -m32"
|
||||
export CXX="$CXX -m32"
|
||||
unset M32 # verilated.mk actually references $(M32) so unset
|
||||
fi
|
||||
|
||||
before_cache:
|
||||
- ccache -s -z
|
||||
|
||||
# All jobs run the same script
|
||||
script: ./ci/travis-script.bash
|
||||
|
||||
# Enumerate all the jobs
|
||||
jobs:
|
||||
include:
|
||||
- if: type != cron
|
||||
stage: "Build Verilator"
|
||||
name: Build Verilator
|
||||
compiler: gcc
|
||||
script: echo "Done building Verilator"
|
||||
# Non-cron build will just run on whatever linux flavor we get
|
||||
- if: type != cron
|
||||
stage: test
|
||||
name: Dist test
|
||||
compiler: gcc
|
||||
script: ci/test.sh dist
|
||||
- if: type != cron
|
||||
stage: test
|
||||
name: Vlt test
|
||||
compiler: gcc
|
||||
script: ci/test.sh vlt
|
||||
- if: type != cron
|
||||
stage: test
|
||||
name: Vltmt set 0 test
|
||||
compiler: gcc
|
||||
script: ci/test.sh vltmt0
|
||||
- if: type != cron
|
||||
stage: test
|
||||
name: Vltmt set 1 test
|
||||
compiler: gcc
|
||||
script: ci/test.sh vltmt1
|
||||
# Cron builds try different OS/compiler combinations
|
||||
- if: type = cron
|
||||
stage: "Build Verilator"
|
||||
name: Build xenial gcc Verilator
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
script: echo "Done building Verilator"
|
||||
- if: type = cron
|
||||
stage: test
|
||||
name: Xenial gcc dist test
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
script: ci/test.sh dist
|
||||
- if: type = cron
|
||||
stage: test
|
||||
name: Xenial gcc vlt test
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
script: ci/test.sh vlt
|
||||
- if: type = cron
|
||||
stage: test
|
||||
name: Xenial gcc vltmt test
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: gcc
|
||||
script: ci/test.sh vltmt
|
||||
- if: type = cron
|
||||
stage: "Build Verilator"
|
||||
name: Build xenial clang Verilator
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: clang
|
||||
script: echo "Done building Verilator"
|
||||
- if: type = cron
|
||||
stage: test
|
||||
name: Xenial clang dist test
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: clang
|
||||
script: ci/test.sh dist
|
||||
- if: type = cron
|
||||
stage: test
|
||||
name: Xenial clang vlt test
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: clang
|
||||
script: ci/test.sh vlt
|
||||
- if: type = cron
|
||||
stage: test
|
||||
name: Xenial clang vltmt test
|
||||
os: linux
|
||||
dist: xenial
|
||||
compiler: clang
|
||||
script: ci/test.sh vltmt
|
||||
# - if: type = cron
|
||||
# stage: "Build Verilator"
|
||||
# name: Build OSX gcc Verilator
|
||||
# os: osx
|
||||
# compiler: gcc
|
||||
# script: echo "Done building Verilator"
|
||||
# - if: type = cron
|
||||
# stage: test
|
||||
# name: OSX gcc dist test
|
||||
# os: osx
|
||||
# compiler: gcc
|
||||
# script: ci/test.sh dist
|
||||
# - if: type = cron
|
||||
# stage: test
|
||||
# name: OSX gcc vlt test
|
||||
# os: osx
|
||||
# compiler: gcc
|
||||
# script: ci/test.sh vlt
|
||||
# - if: type = cron
|
||||
# stage: test
|
||||
# name: OSX gcc vltmt test
|
||||
# os: osx
|
||||
# compiler: gcc
|
||||
# script: ci/test.sh vltmt
|
||||
- if: type = cron
|
||||
stage: "Build Verilator"
|
||||
name: Build trusty gcc Verilator
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: echo "Done building Verilator"
|
||||
- if: type = cron
|
||||
stage: test
|
||||
name: Trusty gcc dist test
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: ci/test.sh dist
|
||||
- if: type = cron
|
||||
stage: test
|
||||
name: Trusty gcc vlt test
|
||||
os: linux
|
||||
dist: trusty
|
||||
compiler: gcc
|
||||
script: ci/test.sh vlt
|
||||
- if: type = cron
|
||||
stage: test
|
||||
os: linux
|
||||
dist: trusty
|
||||
name: Trusty gcc vltmt test
|
||||
compiler: gcc
|
||||
script: ci/test.sh vltmt
|
||||
############################################################################
|
||||
# Jobs in the 'build' stage
|
||||
############################################################################
|
||||
# GCC builds
|
||||
- {stage: build, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {create: {name: trusty-gcc, paths: .}}}
|
||||
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {create: {name: xenial-gcc, paths: .}}}
|
||||
- {stage: build, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {create: {name: bionic-gcc, paths: .}}}
|
||||
- {stage: build, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc, paths: .}}}
|
||||
# Clang builds
|
||||
- {stage: build, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {create: {name: xenial-clang, paths: .}}}
|
||||
- {stage: build, os: linux, dist: focal, compiler: clang, workspaces: {create: {name: focal-clang, paths: .}}}
|
||||
# Coverage build
|
||||
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: coverage, paths: .}}, env: COVERAGE=1}
|
||||
# 32-bit build
|
||||
- {stage: build, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {create: {name: focal-gcc-m32, paths: .}}, env: M32=1}
|
||||
# OS X build
|
||||
- {stage: build, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {create: {name: osx-xcode11.6, paths: .}}}
|
||||
# FreeBSD build
|
||||
#- {stage: build, if: type = cron, os: freebsd, compiler: clang, workspaces: {create: {name: freebsd, paths: .}}}
|
||||
############################################################################
|
||||
# Jobs in the 'test' stage
|
||||
############################################################################
|
||||
# GCC tests
|
||||
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: trusty, compiler: gcc, workspaces: {use: trusty-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: gcc, workspaces: {use: xenial-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: bionic, compiler: gcc, workspaces: {use: bionic-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
# Clang tests
|
||||
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: xenial, compiler: clang, workspaces: {use: xenial-clang}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type != cron, os: linux, dist: focal, compiler: clang, workspaces: {use: focal-clang}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
# Coverage tests
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-dist}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-2}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vlt-3}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-0}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-1}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-2}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: coverage}, git: {clone: false}, env: TESTS=coverage-vltmt-3}
|
||||
# 32-bit tests
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-0]}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=dist-vlt-1]}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-0]}
|
||||
- {stage: test, if: type = cron, os: linux, dist: focal, compiler: gcc, workspaces: {use: focal-gcc-m32}, git: {clone: false}, env: [M32=1, TESTS=vltmt-1]}
|
||||
# OS X tests
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
- {stage: test, if: type = cron, os: osx, osx_image: xcode11.6, compiler: clang, workspaces: {use: osx-xcode11.6}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
# FreeBSD tests
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-0}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=dist-vlt-1}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-0}
|
||||
#- {stage: test, if: type = cron, os: freebsd, compiler: clang, workspaces: {use: freebsd}, git: {clone: false}, env: TESTS=vltmt-1}
|
||||
|
||||
notifications:
|
||||
email:
|
||||
|
||||
@@ -45,6 +45,7 @@ src/Makefile$
|
||||
src/Makefile_obj$
|
||||
include/verilated.mk$
|
||||
test_regress/.gdbinit$
|
||||
codecov.yml
|
||||
config.cache$
|
||||
config.status$
|
||||
verilator\.log
|
||||
|
||||
+16
-6
@@ -89,7 +89,6 @@ datarootdir = @datarootdir@
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
CFG_WITH_THREADED = @CFG_WITH_THREADED@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
@@ -171,6 +170,8 @@ DISTFILES_INC = $(INFOS) .gitignore \
|
||||
test_regress/t/t*/*.v* \
|
||||
test_regress/t/t*/*/*.sv* \
|
||||
test_regress/t/t*/*/*.v* \
|
||||
test_regress/t/t*/*.cpp \
|
||||
test_regress/t/t*/CMakeLists.txt \
|
||||
test_regress/t/*.cpp \
|
||||
test_regress/t/*.h \
|
||||
test_regress/t/*.dat \
|
||||
@@ -336,6 +337,7 @@ installdata:
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib
|
||||
$(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/examples/xml_py
|
||||
cd $(srcdir) \
|
||||
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
@@ -370,8 +372,8 @@ uninstall:
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_c
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_tracing_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/cmake_protect_lib
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/xml_py
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/cmake
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)
|
||||
-rmdir $(DESTDIR)$(pkgconfigdir)
|
||||
|
||||
@@ -424,6 +426,9 @@ CPPCHECK_CPP = $(wildcard \
|
||||
CPPCHECK_H = $(wildcard \
|
||||
$(srcdir)/include/*.h \
|
||||
$(srcdir)/src/*.h )
|
||||
CPPCHECK_YL = $(wildcard \
|
||||
$(srcdir)/src/*.y \
|
||||
$(srcdir)/src/*.l )
|
||||
CPPCHECK = src/cppcheck_filtered
|
||||
CPPCHECK_FLAGS = --enable=all --inline-suppr \
|
||||
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
|
||||
@@ -434,7 +439,7 @@ 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 $(CPPCHECK_INC) $<
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
|
||||
|
||||
CLANGTIDY = clang-tidy
|
||||
CLANGTIDY_FLAGS = -config=''
|
||||
@@ -455,6 +460,14 @@ analyzer-include:
|
||||
-rm -rf examples/*/obj*
|
||||
scan-build $(MAKE) -k examples
|
||||
|
||||
CLANGFORMAT = clang-format
|
||||
CLANGFORMAT_FLAGS = -i
|
||||
|
||||
clang-format:
|
||||
@$(CLANGFORMAT) --version | egrep 10.0 > /dev/null \
|
||||
|| echo "*** You are not using clang-format 10.0, indents may differ from master's ***"
|
||||
$(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL)
|
||||
|
||||
ftp: info
|
||||
|
||||
install-msg:
|
||||
@@ -534,9 +547,6 @@ dist-file-list:
|
||||
@echo $(wildcard $(DISTFILES))
|
||||
@echo "end-dist-file-list:"; # Scripts look for this
|
||||
|
||||
print-cfg-with-threaded:
|
||||
@echo $(CFG_WITH_THREADED)
|
||||
|
||||
######################################################################
|
||||
# Distributions
|
||||
|
||||
|
||||
+24
-21
@@ -4,7 +4,8 @@
|
||||
ifdef::env-github[]
|
||||
image:https://img.shields.io/badge/License-LGPL%20v3-blue.svg[license LGPLv3,link=https://www.gnu.org/licenses/lgpl-3.0]
|
||||
image:https://img.shields.io/badge/License-Artistic%202.0-0298c3.svg[license Artistic-2.0,link=https://opensource.org/licenses/Artistic-2.0]
|
||||
image:https://api.codacy.com/project/badge/Grade/48478c986f13400682ffe4a5e0939b3a[Code Quality,link=https://www.codacy.com/gh/verilator/verilator]
|
||||
image:https://api.codacy.com/project/badge/Grade/fa78caa433c84a4ab9049c43e9debc6f[Code Quality,link=https://www.codacy.com/gh/verilator/verilator]
|
||||
image:https://codecov.io/gh/verilator/verilator/branch/master/graph/badge.svg[Coverage,link=https://codecov.io/gh/verilator/verilator]
|
||||
image:https://travis-ci.com/verilator/verilator.svg?branch=master[Build Status (Travis CI),link=https://travis-ci.com/verilator/verilator]
|
||||
endif::[]
|
||||
|
||||
@@ -20,9 +21,9 @@ endif::[]
|
||||
|
||||
== Welcome to Verilator
|
||||
|
||||
[cols="a,a",indent=0,frame="none"]
|
||||
[cols="a,a",indent=0,frame="none",grid="rows"]
|
||||
|===
|
||||
^.^| *Welcome to Verilator, the fastest free Verilog HDL simulator.*
|
||||
^.^| *Welcome to Verilator, the fastest Verilog/SystemVerilog simulator.*
|
||||
+++ <br/> +++ • Accepts synthesizable Verilog or SystemVerilog
|
||||
+++ <br/> +++ • Performs lint code-quality checks
|
||||
+++ <br/> +++ • Compiles into multithreaded {cpp}, or SystemC
|
||||
@@ -56,7 +57,7 @@ endif::[]
|
||||
== What Verilator Does
|
||||
|
||||
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
|
||||
"Verilates" the specified synthesizable Verilog or SystemVerilog code by
|
||||
"Verilates" the specified Verilog or SystemVerilog code by
|
||||
reading it, performing lint checks, and optionally inserting assertion
|
||||
checks and coverage-analysis points. It outputs single- or multi-threaded
|
||||
.cpp and .h files, the "Verilated" code.
|
||||
@@ -72,30 +73,30 @@ Verilator may not be the best choice if you are expecting a full featured
|
||||
replacement for NC-Verilog, VCS or another commercial Verilog simulator, or
|
||||
if you are looking for a behavioral Verilog simulator e.g. for a quick
|
||||
class project (we recommend http://iverilog.icarus.com[Icarus Verilog] for
|
||||
this.) However, if you are looking for a path to migrate synthesizable
|
||||
Verilog to {cpp} or SystemC, and your team is comfortable writing just a
|
||||
touch of {cpp} code, Verilator is the tool for you.
|
||||
this.) However, if you are looking for a path to migrate SystemVerilog to
|
||||
{cpp} or SystemC, or your team is comfortable writing just a touch of {cpp}
|
||||
code, Verilator is the tool for you.
|
||||
|
||||
== Performance
|
||||
|
||||
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather
|
||||
than only translate, Verilator compiles your code into a much faster
|
||||
optimized and optionally thread-partitioned model, which is in turn wrapped
|
||||
inside a {cpp}/SystemC/{cpp}-under-Python module. The results are a compiled Verilog
|
||||
model that executes even on a single-thread over 10x faster than standalone
|
||||
SystemC, and on a single thread is about 100 times faster than interpreted
|
||||
Verilog simulators such as http://iverilog.icarus.com[Icarus
|
||||
Verilator does not simply convert Verilog HDL to {cpp} or SystemC. Rather,
|
||||
Verilator compiles your code into a much faster optimized and optionally
|
||||
thread-partitioned model, which is in turn wrapped inside a
|
||||
{cpp}/SystemC module. The results are a compiled
|
||||
Verilog model that executes even on a single-thread over 10x faster than
|
||||
standalone SystemC, and on a single thread is about 100 times faster than
|
||||
interpreted Verilog simulators such as http://iverilog.icarus.com[Icarus
|
||||
Verilog]. Another 2-10x speedup might be gained from multithreading
|
||||
(yielding 200-1000x total over interpreted simulators).
|
||||
|
||||
Verilator has typically similar or better performance versus the commercial
|
||||
Verilog simulators (Carbon Design Systems Carbonator, Modelsim, Cadence
|
||||
Incisive/NC-Verilog, Synopsys VCS, VTOC, and Pragmatic CVer/CVC). But,
|
||||
Verilator is free, so you can spend on computes rather than licenses. Thus
|
||||
Verilator gives you more cycles/dollar than anything else available.
|
||||
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.
|
||||
|
||||
For more information on how Verilator stacks up to some of the other
|
||||
commercial and free Verilog simulators, see the
|
||||
closed-sourced and open-sourced Verilog simulators, see the
|
||||
https://www.veripool.org/verilog_sim_benchmarks.html[Verilog Simulator
|
||||
Benchmarks]. (If you benchmark Verilator, please see the notes in the
|
||||
https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)], and also
|
||||
@@ -112,9 +113,11 @@ For more information:
|
||||
* https://verilator.org/verilator_doc.html[Verilator manual (HTML)],
|
||||
or https://verilator.org/verilator_doc.pdf[Verilator manual (PDF)]
|
||||
|
||||
* https://github.com/verilator/verilator-announce[Subscribe to verilator announcements]
|
||||
|
||||
* https://verilator.org/forum[Verilator forum]
|
||||
|
||||
* https://verilator.org/issues[Verilator Issues]
|
||||
* https://verilator.org/issues[Verilator issues]
|
||||
|
||||
== Support
|
||||
|
||||
|
||||
+926
-643
File diff suppressed because it is too large
Load Diff
+17
-3
@@ -156,6 +156,8 @@ verilator_coverage - Verilator coverage analyzer
|
||||
|
||||
verilator_coverage -write merged.dat -read <datafiles>...
|
||||
|
||||
verilator_coverage -write-info merged.info -read <datafiles>...
|
||||
|
||||
Verilator_coverage processes Verilator coverage reports.
|
||||
|
||||
With --anotate, it reads the specified data file and generates annotated
|
||||
@@ -224,8 +226,20 @@ Displays program version and exits.
|
||||
=item --write I<filename>
|
||||
|
||||
Specifies the aggregate coverage results, summed across all the files,
|
||||
should be written to the given filename. This is useful in scripts to
|
||||
combine many sequential runs into one master coverage file.
|
||||
should be written to the given filename in verilator_coverage data format.
|
||||
This is useful in scripts to combine many sequential runs into one master
|
||||
coverage file.
|
||||
|
||||
=item --write-info I<filename.info>
|
||||
|
||||
Specifies the aggregate coverage results, summed across all the files,
|
||||
should be written to the given filename in C<lcov> .info format.
|
||||
This may be used to use C<lcov> to aggregate or generate reports.
|
||||
|
||||
The info format loses data compared to the Verilator coverage data format;
|
||||
the info will all forms of coverage converted to line style coverage, and
|
||||
if there are multiple coverage points on a single line, the minimum
|
||||
coverage across those points will be used to report coverage of the line.
|
||||
|
||||
=back
|
||||
|
||||
@@ -277,7 +291,7 @@ Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
C<verilator>
|
||||
C<verilator>, C<lcov>
|
||||
|
||||
L<verilator_coverage --help> which is the source for this document.
|
||||
|
||||
|
||||
+8
-1
@@ -156,7 +156,8 @@ sub report {
|
||||
print "\nAnalysis:\n";
|
||||
printf " Total threads = %d\n", $nthreads;
|
||||
printf " Total mtasks = %d\n", scalar(keys %Mtasks);
|
||||
printf " Total cpus used = %d\n", scalar(keys %{$Global{cpus}});
|
||||
my $ncpus = scalar(keys %{$Global{cpus}});
|
||||
printf " Total cpus used = %d\n", $ncpus;
|
||||
printf " Total yields = %d\n", $Global{stats}{yields};
|
||||
printf " Total eval time = %d rdtsc ticks\n", $Global{last_end};
|
||||
printf " Longest mtask time = %d rdtsc ticks\n", $long_mtask_time;
|
||||
@@ -206,6 +207,12 @@ sub report {
|
||||
print " stddev = " . ($stddev) . "\n";
|
||||
print " e ^ stddev = " . exp($stddev). "\n";
|
||||
print "\n";
|
||||
|
||||
if ($nthreads > $ncpus) {
|
||||
print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n";
|
||||
print " : See docs on use of numactl.\n";
|
||||
print "\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub report_graph {
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
#!/bin/bash
|
||||
# DESCRIPTION: Verilator: Build script for vcddiff
|
||||
#
|
||||
# Copyright 2019 by Todd Strader. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
set -e
|
||||
|
||||
# NB: it would be better to add this via a PPA
|
||||
|
||||
TMP_DIR=$(mktemp -d)
|
||||
|
||||
git -C "${TMP_DIR}" clone https://github.com/veripool/vcddiff
|
||||
VCDDIFF_DIR=${TMP_DIR}/vcddiff
|
||||
git -C "${VCDDIFF_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
|
||||
make -C "${VCDDIFF_DIR}"
|
||||
sudo cp "${VCDDIFF_DIR}/vcddiff" /usr/local/bin
|
||||
@@ -1,65 +0,0 @@
|
||||
#!/bin/bash
|
||||
# DESCRIPTION: Verilator: Travis CI build script
|
||||
#
|
||||
# Copyright 2019 by Todd Strader. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
#
|
||||
# This script builds and caches the Verilator binaries for Travis CI
|
||||
# (and possibly other CI platforms). The Verilator CI system uses this
|
||||
# script, but other CI systems that depend on Verilator may also use
|
||||
# the script.
|
||||
# see: https://github.com/verilator/verilator_ext_tests/blob/master/.travis.yml
|
||||
# To use this script, either checkout Verilator as part of the CI build
|
||||
# process or add Verilator as a Git submodule. Verilator tarballs can
|
||||
# not be used as the script relies on Git revisions for caching.
|
||||
set -e
|
||||
|
||||
if [ -z "${VERILATOR_NUM_JOBS}" ]; then
|
||||
VERILATOR_NUM_JOBS=$(nproc)
|
||||
fi
|
||||
|
||||
# Caching would be simpler if we installed without VERILATOR_ROOT, but
|
||||
# it's needed for driver.pl outside of the repo
|
||||
if [ -z "${VERILATOR_ROOT}" ]; then
|
||||
echo "VERILATOR_ROOT not set"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
if [ -z "${VERILATOR_CACHE}" ]; then
|
||||
echo "VERILATOR_CACHE not set"
|
||||
exit -1
|
||||
fi
|
||||
|
||||
VERILATOR_REV=$(cd "${VERILATOR_ROOT}" && git rev-parse HEAD)
|
||||
echo "Found Verilator rev ${VERILATOR_REV}"
|
||||
|
||||
CACHED_REV_FILE=${VERILATOR_CACHE}/.rev.txt
|
||||
|
||||
if [[ ! -f "${CACHED_REV_FILE}" || \
|
||||
$(< "${CACHED_REV_FILE}") != "${VERILATOR_REV}" ]]; then
|
||||
echo "Building Verilator"
|
||||
|
||||
# Unsure why Travis monkies with the capitalization of the stage name, but it does
|
||||
if [[ -n ${TRAVIS_BUILD_STAGE_NAME} && \
|
||||
${TRAVIS_BUILD_STAGE_NAME} != "Build verilator" ]]; then
|
||||
echo "WARNING: Building Verilator in Travis build stage other than \"Build verilator\": ${TRAVIS_BUILD_STAGE_NAME}"
|
||||
fi
|
||||
|
||||
cd "${VERILATOR_ROOT}"
|
||||
autoconf && ./configure ${VERILATOR_CONFIG_FLAGS} && make -j ${VERILATOR_NUM_JOBS}
|
||||
# Copy the Verilator build artifacts
|
||||
mkdir -p "${VERILATOR_CACHE}"
|
||||
rm -rf ${VERILATOR_CACHE}/*
|
||||
cp bin/*bin* "${VERILATOR_CACHE}"
|
||||
# Remember the Git revision
|
||||
echo "${VERILATOR_REV}" > "${CACHED_REV_FILE}"
|
||||
else
|
||||
echo "Using cached Verilator"
|
||||
cd "${VERILATOR_ROOT}"
|
||||
# Create include/verilated_config.h and maybe other things
|
||||
autoconf && ./configure ${VERILATOR_CONFIG_FLAGS}
|
||||
cp ${VERILATOR_CACHE}/* bin
|
||||
fi
|
||||
@@ -6,44 +6,40 @@
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
FROM ubuntu:18.04
|
||||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update \
|
||||
&& DEBIAN_FRONTEND=noninteractive \
|
||||
apt-get install --no-install-recommends -y \
|
||||
autoconf=2.69-11 \
|
||||
bc=1.07.1-2 \
|
||||
bison=2:3.0.4.dfsg-1build1 \
|
||||
build-essential=12.4ubuntu1 \
|
||||
ca-certificates=20180409 \
|
||||
cmake=3.10.2-1ubuntu2.18.04.1 \
|
||||
flex=2.6.4-6 \
|
||||
gdb=8.1-0ubuntu3.2 \
|
||||
gcc-6=6.5.0-2ubuntu1~18.04 \
|
||||
gcc-5=5.5.0-12ubuntu1 \
|
||||
gcc-4.8=4.8.5-4ubuntu8 \
|
||||
git=1:2.17.1-1ubuntu0.5 \
|
||||
gtkwave=3.3.86-1 \
|
||||
g++-6=6.5.0-2ubuntu1~18.04 \
|
||||
g++-5=5.5.0-12ubuntu1 \
|
||||
g++-4.8=4.8.5-4ubuntu8 \
|
||||
libfl2=2.6.4-6 \
|
||||
libfl-dev=2.6.4-6 \
|
||||
numactl=2.0.11-2.1ubuntu0.1 \
|
||||
perl=5.26.1-6ubuntu0.3 \
|
||||
python3=3.6.7-1~18.04 \
|
||||
wget=1.19.4-1ubuntu2.2 \
|
||||
zlibc=0.9k-4.3 \
|
||||
zlib1g=1:1.2.11.dfsg-0ubuntu2 \
|
||||
zlib1g-dev=1:1.2.11.dfsg-0ubuntu2 \
|
||||
autoconf \
|
||||
bc \
|
||||
bison \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
ccache \
|
||||
clang \
|
||||
cmake \
|
||||
flex \
|
||||
gdb \
|
||||
git \
|
||||
gtkwave \
|
||||
libfl2 \
|
||||
libfl-dev \
|
||||
libgoogle-perftools-dev \
|
||||
libsystemc \
|
||||
libsystemc-dev \
|
||||
numactl \
|
||||
perl \
|
||||
python3 \
|
||||
wget \
|
||||
zlibc \
|
||||
zlib1g \
|
||||
zlib1g-dev \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
WORKDIR /tmp
|
||||
|
||||
COPY build-systemc.sh /tmp/
|
||||
RUN ./build-systemc.sh
|
||||
|
||||
RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector
|
||||
|
||||
RUN git clone https://github.com/veripool/vcddiff.git && \
|
||||
@@ -55,4 +51,6 @@ COPY build.sh /tmp/build.sh
|
||||
|
||||
ENV VERILATOR_AUTHOR_SITE=1
|
||||
|
||||
WORKDIR /work
|
||||
|
||||
ENTRYPOINT [ "/tmp/build.sh" ]
|
||||
|
||||
@@ -5,7 +5,7 @@ build. It uses the following parameters:
|
||||
|
||||
* Source repository (default: https://github.com/verilator/verilator)
|
||||
* Source revision (default: master)
|
||||
* GCC version (4.8.5, 5.5.0, 6.5.0, 7.4.0, default: 7.4.0)
|
||||
* Compiler (GCC 9.3.0, clang 10.0.0, default: 9.3.0)
|
||||
|
||||
The container is published as `verilator/verilator-buildenv` on
|
||||
https://hub.docker.com/repository/docker/verilator/verilator-buildenv[docker hub].
|
||||
@@ -20,13 +20,13 @@ To also run tests:
|
||||
|
||||
To change the compiler:
|
||||
|
||||
docker run -ti -e CC=gcc-4.8 -e CXX=g++-4.8 verilator/verilator-buildenv test
|
||||
docker run -ti -e CC=clang-10 -e CXX=clang++-10 verilator/verilator-buildenv test
|
||||
|
||||
The tests that involve gdb are not working due to security restrictions.
|
||||
To run those too:
|
||||
|
||||
....
|
||||
docker run -ti -v ${PWD}:/tmp/repo -e REPO=/tmp/repo -e REV=`git rev-parse --short HEAD` -e CC=gcc-4.8 -e CXX=g++-4.8 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined verilator/verilator-buildenv test
|
||||
docker run -ti -e CC=clang-10 -e CXX=clang++-10 --cap-add=SYS_PTRACE --security-opt seccomp=unconfined verilator/verilator-buildenv test
|
||||
....
|
||||
|
||||
Rather then building using a remote git repository you may prefer to use a
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
#!/bin/bash -e
|
||||
# DESCRIPTION: Build SystemC in Ubuntu 18.04 with different g++/gcc
|
||||
#
|
||||
# Copyright 2020 by Stefan Wallentowitz. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
build_variant () {
|
||||
version=$($1 --version | grep gcc | awk '{print $4}')
|
||||
mkdir "/usr/local/systemc-2.3.3-gcc$version"
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --prefix="/usr/local/systemc-2.3.3-gcc$version" CC="$1" CXX="$2" LD="$2"
|
||||
make -j
|
||||
make install
|
||||
cd ..
|
||||
rm -r build
|
||||
}
|
||||
|
||||
wget https://www.accellera.org/images/downloads/standards/systemc/systemc-2.3.3.tar.gz
|
||||
tar -xzf systemc-2.3.3.tar.gz
|
||||
cd systemc-2.3.3
|
||||
build_variant gcc g++
|
||||
build_variant gcc-6 g++-6
|
||||
build_variant gcc-5 g++-5
|
||||
build_variant gcc-4.8 g++-4.8
|
||||
cd ..
|
||||
rm -r systemc-2.3.3*
|
||||
@@ -12,12 +12,6 @@
|
||||
: "${CC:=gcc}"
|
||||
: "${CXX:=g++}"
|
||||
|
||||
GCCVERSION=$(${CC} --version | grep gcc | awk '{print $4}')
|
||||
|
||||
export SYSTEMC_INCLUDE="/usr/local/systemc-2.3.3-gcc${GCCVERSION}/include"
|
||||
export SYSTEMC_LIBDIR="/usr/local/systemc-2.3.3-gcc${GCCVERSION}/lib-linux64"
|
||||
export LD_LIBRARY_PATH=${SYSTEMC_LIBDIR}
|
||||
|
||||
SRCS=$PWD/verilator
|
||||
|
||||
git clone "$REPO" "$SRCS"
|
||||
|
||||
+14
-11
@@ -6,20 +6,23 @@
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
FROM ubuntu:18.04
|
||||
FROM ubuntu:20.04
|
||||
|
||||
RUN apt-get update \
|
||||
&& DEBIAN_FRONTEND=noninteractive \
|
||||
&& apt-get install --no-install-recommends -y \
|
||||
autoconf=2.69-11 \
|
||||
bc=1.07.1-2 \
|
||||
bison=2:3.0.4.dfsg-1build1 \
|
||||
build-essential=12.4ubuntu1 \
|
||||
ca-certificates=20180409 \
|
||||
flex=2.6.4-6 \
|
||||
git=1:2.17.1-1ubuntu0.5 \
|
||||
libfl-dev=2.6.4-6 \
|
||||
perl=5.26.1-6ubuntu0.3 \
|
||||
python3=3.6.7-1~18.04 \
|
||||
autoconf \
|
||||
bc \
|
||||
bison \
|
||||
build-essential \
|
||||
ca-certificates \
|
||||
ccache \
|
||||
flex \
|
||||
git \
|
||||
libfl-dev \
|
||||
libgoogle-perftools-dev \
|
||||
perl \
|
||||
python3 \
|
||||
&& apt-get clean \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
|
||||
-34
@@ -1,34 +0,0 @@
|
||||
#!/bin/bash
|
||||
# DESCRIPTION: Verilator: Travis CI test script
|
||||
#
|
||||
# Copyright 2019 by Todd Strader. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
set -e
|
||||
|
||||
export DRIVER_FLAGS='-j 0 --quiet --rerun'
|
||||
|
||||
case $1 in
|
||||
dist)
|
||||
make -C test_regress SCENARIOS=--dist
|
||||
;;
|
||||
vlt)
|
||||
make -C test_regress SCENARIOS=--vlt
|
||||
;;
|
||||
vltmt)
|
||||
make -C test_regress SCENARIOS=--vltmt
|
||||
;;
|
||||
vltmt0)
|
||||
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
|
||||
;;
|
||||
vltmt1)
|
||||
make -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
|
||||
;;
|
||||
*)
|
||||
echo "Usage: test.sh (dist|vlt|vltmt)"
|
||||
exit -1
|
||||
;;
|
||||
esac
|
||||
Executable
+29
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# DESCRIPTION: Verilator: Travis CI ccache maintenance
|
||||
#
|
||||
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
################################################################################
|
||||
# This script is run in 'before_script', once ccache has been set up.
|
||||
################################################################################
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
# Show version
|
||||
ccache --version
|
||||
|
||||
# Flush ccache if requested in commit message
|
||||
COMMIT="${TRAVIS_PULL_REQUEST_SHA:-$TRAVIS_COMMIT}"
|
||||
if git log --format=%B -n 1 "$COMMIT" | grep -q -i '\[travis\s\+ccache\s\+clear\]'; then
|
||||
echo "Flushing ccache due to commit message"
|
||||
ccache -C
|
||||
fi
|
||||
|
||||
# Dump stats, then zero stats
|
||||
ccache -s -z
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
# DESCRIPTION: Verilator: Travis CI ccache sizer
|
||||
#
|
||||
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
################################################################################
|
||||
# This script computes the size of the ccache to be used for a job. We want the
|
||||
# ccache to be just big enough to be able to hold a whole build so a re-build
|
||||
# of the same does not miss in the cache due to capacity, but we don't want the
|
||||
# ccache too big as pulling it down from the network takes time, and it is
|
||||
# unlikely objects from much earlier builds would be useful.
|
||||
################################################################################
|
||||
|
||||
fatal() {
|
||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||
}
|
||||
|
||||
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||
if [ "$COVERAGE" == 1 ]; then
|
||||
echo "1024M"
|
||||
else
|
||||
echo "768M"
|
||||
fi
|
||||
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||
if [[ $TESTS == coverage-* ]]; then
|
||||
echo "1536M"
|
||||
else
|
||||
echo "256M"
|
||||
fi
|
||||
else
|
||||
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
|
||||
fi
|
||||
Executable
+104
@@ -0,0 +1,104 @@
|
||||
#!/usr/bin/env bash
|
||||
# DESCRIPTION: Verilator: Travis CI dependency install script
|
||||
#
|
||||
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
################################################################################
|
||||
# This script runs in the 'install' phase of all jobs, in all stages. We try to
|
||||
# minimize the time spent in this by selectively installing only the components
|
||||
# required by the particular build stage.
|
||||
################################################################################
|
||||
|
||||
# Note that Travis runs "apt-get update" when "apt-get install" is used in the
|
||||
# .travis.yml file directly, but since we invoke it via this script, we need to
|
||||
# run it manually where requried, otherwise some packages cannot be found.
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
fatal() {
|
||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||
}
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
MAKE=make
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
MAKE=make
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
MAKE=gmake
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
fi
|
||||
|
||||
install-vcddiff() {
|
||||
TMP_DIR="$(mktemp -d)"
|
||||
git clone https://github.com/veripool/vcddiff "$TMP_DIR"
|
||||
git -C "${TMP_DIR}" checkout 5112f88b7ba8818dce9dfb72619e64a1fc19542c
|
||||
"$MAKE" -C "${TMP_DIR}"
|
||||
sudo cp "${TMP_DIR}/vcddiff" /usr/local/bin
|
||||
}
|
||||
|
||||
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||
##############################################################################
|
||||
# Dependencies of jobs in the 'build' stage, i.e.: packages required to
|
||||
# build Verilator
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install libfl-dev
|
||||
sudo apt-get install libgoogle-perftools-dev
|
||||
if [ "$COVERAGE" = 1 ]; then
|
||||
yes yes | sudo cpan -fi Unix::Processors Parallel::Forker
|
||||
fi
|
||||
if [ "$M32" = 1 ]; then
|
||||
sudo apt-get install gcc-multilib g++-multilib
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew update
|
||||
brew install ccache perl gperftools
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
sudo pkg install -y autoconf bison ccache gmake perl5
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
fi
|
||||
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||
##############################################################################
|
||||
# Dependencies of jobs in the 'test' stage, i.e.: packages required to
|
||||
# run the tests
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install gdb gtkwave lcov
|
||||
if [ "$TRAVIS_DIST" = "focal" ]; then
|
||||
sudo apt-get install libsystemc-dev
|
||||
fi
|
||||
if [ "$M32" = 1 ]; then
|
||||
sudo apt-get install lib32z1-dev gcc-multilib g++-multilib
|
||||
fi
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
brew update
|
||||
# brew cask install gtkwave # fst2vcd hangs at launch, so don't bother
|
||||
brew install ccache perl
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
# fst2vcd fails with "Could not open '<input file>', exiting."
|
||||
sudo pkg install -y ccache gmake perl5 python3
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
fi
|
||||
# Common installs
|
||||
if [ "$TRAVIS_DIST" != "trusty" ]; then
|
||||
TRAVIS_CPAN_REPO=https://cpan.org
|
||||
fi
|
||||
# Not listing Bit::Vector as slow to install, and only skips one test
|
||||
yes yes | sudo cpan -M $TRAVIS_CPAN_REPO -fi Unix::Processors Parallel::Forker
|
||||
install-vcddiff
|
||||
else
|
||||
##############################################################################
|
||||
# Unknown build stage
|
||||
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
|
||||
fi
|
||||
Executable
+134
@@ -0,0 +1,134 @@
|
||||
#!/usr/bin/env bash
|
||||
# DESCRIPTION: Verilator: Travis CI main job script
|
||||
#
|
||||
# Copyright 2020 by Geza Lore. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
#
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
################################################################################
|
||||
# This is the main script executed in the 'script' phase by all jobs. We use a
|
||||
# single script to keep the .travis.yml spec simple. We pass job parameters via
|
||||
# environment variables using 'env' keys. Having different 'env' keys in jobs
|
||||
# ensures they use different Travis build caches.
|
||||
################################################################################
|
||||
|
||||
set -e
|
||||
set -x
|
||||
|
||||
fatal() {
|
||||
echo "ERROR: $(basename "$0"): $1" >&2; exit 1;
|
||||
}
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "linux" ]; then
|
||||
export MAKE=make
|
||||
NPROC=$(nproc)
|
||||
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
export MAKE=make
|
||||
NPROC=$(sysctl -n hw.logicalcpu)
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
export MAKE=gmake
|
||||
NPROC=$(sysctl -n hw.ncpu)
|
||||
else
|
||||
fatal "Unknown os: '$TRAVIS_OS_NAME'"
|
||||
fi
|
||||
|
||||
if [ "$TRAVIS_BUILD_STAGE_NAME" = "build" ]; then
|
||||
##############################################################################
|
||||
# Build verilator
|
||||
|
||||
if [ "$COVERAGE" != 1 ]; then
|
||||
autoconf
|
||||
./configure --enable-longtests --enable-ccwarn
|
||||
"$MAKE" -j "$NPROC" -k
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
file bin/verilator_bin
|
||||
file bin/verilator_bin_dbg
|
||||
md5 bin/verilator_bin
|
||||
md5 bin/verilator_bin_dbg
|
||||
stat bin/verilator_bin
|
||||
stat bin/verilator_bin_dbg
|
||||
fi
|
||||
else
|
||||
nodist/code_coverage --stages 1-2
|
||||
fi
|
||||
elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then
|
||||
##############################################################################
|
||||
# Run tests
|
||||
|
||||
if [ "$TRAVIS_OS_NAME" = "osx" ]; then
|
||||
export VERILATOR_TEST_NO_GDB=1 # Pain to get GDB to work on OS X
|
||||
export VERILATOR_TEST_NO_GPROF=1 # Apple Clang has no -pg
|
||||
# export PATH="/Applications/gtkwave.app/Contents/Resources/bin:$PATH" # fst2vcd
|
||||
file bin/verilator_bin
|
||||
file bin/verilator_bin_dbg
|
||||
md5 bin/verilator_bin
|
||||
md5 bin/verilator_bin_dbg
|
||||
stat bin/verilator_bin
|
||||
stat bin/verilator_bin_dbg
|
||||
# For some reason, the dbg exe is corrupted by this point ('file' reports
|
||||
# it as data rather than a Mach-O). Unclear if this is an OS X issue or
|
||||
# one for Travis. Remove the file and re-link...
|
||||
rm bin/verilator_bin_dbg
|
||||
"$MAKE" -j "$NPROC" -k
|
||||
elif [ "$TRAVIS_OS_NAME" = "freebsd" ]; then
|
||||
export VERILATOR_TEST_NO_GDB=1 # Disable for now, ideally should run
|
||||
export VERILATOR_TEST_NO_GPROF=1 # gprof is a bit different on FreeBSD, disable
|
||||
fi
|
||||
|
||||
# Run the specified test
|
||||
case $TESTS in
|
||||
dist-vlt-0)
|
||||
"$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=0/2
|
||||
;;
|
||||
dist-vlt-1)
|
||||
"$MAKE" -C test_regress SCENARIOS="--dist --vlt" DRIVER_HASHSET=--hashset=1/2
|
||||
;;
|
||||
vltmt-0)
|
||||
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2
|
||||
;;
|
||||
vltmt-1)
|
||||
"$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=1/2
|
||||
;;
|
||||
coverage-dist)
|
||||
nodist/code_coverage --stages 3- --scenarios=--dist
|
||||
;;
|
||||
coverage-vlt-0)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=0/4
|
||||
;;
|
||||
coverage-vlt-1)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=1/4
|
||||
;;
|
||||
coverage-vlt-2)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=2/4
|
||||
;;
|
||||
coverage-vlt-3)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vlt --hashset=3/4
|
||||
;;
|
||||
coverage-vltmt-0)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=0/4
|
||||
;;
|
||||
coverage-vltmt-1)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=1/4
|
||||
;;
|
||||
coverage-vltmt-2)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=2/4
|
||||
;;
|
||||
coverage-vltmt-3)
|
||||
nodist/code_coverage --stages 3- --scenarios=--vltmt --hashset=3/4
|
||||
;;
|
||||
*)
|
||||
fatal "Unknown test: $TESTS"
|
||||
;;
|
||||
esac
|
||||
# Upload coverage data to codecov.io
|
||||
if [[ $TESTS == coverage-* ]]; then
|
||||
bash <(curl -s https://codecov.io/bash) -f nodist/obj_dir/coverage/app_total.info
|
||||
fi
|
||||
else
|
||||
##############################################################################
|
||||
# Unknown build stage
|
||||
fatal "Unknown build stage: '$TRAVIS_BUILD_STAGE_NAME'"
|
||||
fi
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
# DESCRIPTION: codecov.io config
|
||||
#
|
||||
# Copyright 2020-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
####################
|
||||
# Validate:
|
||||
# curl --data-binary @codecov.yml https://codecov.io/validate
|
||||
|
||||
codecov:
|
||||
require_ci_to_pass: no
|
||||
|
||||
coverage:
|
||||
precision: 2
|
||||
round: down
|
||||
range: "70...100"
|
||||
ignore:
|
||||
- "ci"
|
||||
- "docs"
|
||||
- "examples"
|
||||
- "include/gtkwave"
|
||||
- "include/vltstd"
|
||||
- "test_regress"
|
||||
|
||||
parsers:
|
||||
gcov:
|
||||
branch_detection:
|
||||
conditional: yes
|
||||
loop: yes
|
||||
method: no
|
||||
macro: no
|
||||
|
||||
comment:
|
||||
layout: "reach,diff,flags,tree"
|
||||
behavior: default
|
||||
require_changes: yes
|
||||
+67
-43
@@ -7,16 +7,20 @@
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[4.032 2020-04-04],
|
||||
AC_INIT([Verilator],[4.102 2020-10-15],
|
||||
[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_CONFIG_HEADER(src/config_build.h)
|
||||
AC_CONFIG_FILES(Makefile docs/Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc verilator-config.cmake verilator-config-version.cmake)
|
||||
|
||||
# Version
|
||||
AC_MSG_RESULT([configuring for $PACKAGE_STRING])
|
||||
PACKAGE_VERSION_NUMBER=`AS_ECHO("$PACKAGE_VERSION") | sed 's/ .*//g'`
|
||||
AC_SUBST(PACKAGE_VERSION_NUMBER)
|
||||
|
||||
# Ignore automake flags passed by Ubuntu builds
|
||||
AC_ARG_ENABLE([dependency-tracking],
|
||||
@@ -109,27 +113,11 @@ AC_ARG_ENABLE([longtests],
|
||||
AC_SUBST(CFG_WITH_LONGTESTS)
|
||||
AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
||||
|
||||
# CFG_WITH_PREC11
|
||||
AC_MSG_CHECKING(whether allow pre-C++11)
|
||||
AC_ARG_ENABLE([prec11],
|
||||
[AS_HELP_STRING([--enable-prec11],
|
||||
[enable pre-C++11 compilers for Verilator binary
|
||||
and Verilated makefiles])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_PREC11=yes ;;
|
||||
no) CFG_WITH_PREC11=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-prec11]) ;;
|
||||
esac],
|
||||
[CFG_WITH_PREC11=no;]
|
||||
)
|
||||
AC_SUBST(CFG_WITH_PREC11)
|
||||
AC_MSG_RESULT($CFG_WITH_PREC11)
|
||||
|
||||
# Compiler flags
|
||||
CFLAGS+=" -I${includedir}"
|
||||
CPPFLAGS+=" -I${includedir}"
|
||||
CXXFLAGS+=" -I${includedir}"
|
||||
LDFLAGS+=" -L${libdir}"
|
||||
# Compiler flags (ensure they are not empty to avoid configure defaults)
|
||||
CFLAGS+=" "
|
||||
CPPFLAGS+=" "
|
||||
CXXFLAGS+=" "
|
||||
LDFLAGS+=" "
|
||||
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
@@ -150,14 +138,26 @@ AC_PATH_PROG(PERL,perl)
|
||||
if test "x$PERL" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "perl" in your PATH, please install it])
|
||||
fi
|
||||
|
||||
AC_PATH_PROG(LEX,flex)
|
||||
if test "x$LEX" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "flex" in your PATH, please install it])
|
||||
fi
|
||||
flex_version=$($LEX --version | head -1)
|
||||
AC_MSG_RESULT([$LEX --version = $flex_version])
|
||||
|
||||
AC_PATH_PROG(YACC,bison)
|
||||
if test "x$YACC" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
||||
fi
|
||||
bison_version=$($YACC --version | head -1)
|
||||
AC_MSG_RESULT([$YACC --version = $bison_version])
|
||||
|
||||
AC_CHECK_PROG(OBJCACHE,ccache,ccache)
|
||||
if test "x$OBJCACHE" != "x" ; then
|
||||
objcache_version=$($OBJCACHE --version | head -1)
|
||||
AC_MSG_RESULT([objcache is $OBJCACHE --version = $objcache_version])
|
||||
fi
|
||||
|
||||
# Checks for libraries.
|
||||
|
||||
@@ -328,6 +328,7 @@ m4_foreach([cflag],[
|
||||
[-mno-cet],
|
||||
[-Qunused-arguments],
|
||||
[-Wno-bool-operation],
|
||||
[-Wno-tautological-bitwise-compare],
|
||||
[-Wno-parentheses-equality],
|
||||
[-Wno-sign-compare],
|
||||
[-Wno-uninitialized],
|
||||
@@ -393,12 +394,17 @@ _MY_LDLIBS_CHECK_IFELSE(
|
||||
fi])
|
||||
AC_SUBST(CFG_LIBS)
|
||||
|
||||
# Set CFG_WITH_THREADED if can support threading
|
||||
AC_MSG_CHECKING(whether $CXX supports Verilated threads)
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_STD_NEWEST $CFG_CXXFLAGS_NO_UNUSED"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <thread>], [[ ]])],
|
||||
# Need C++11 at least
|
||||
#Alternative: AX_CXX_COMPILE_STDCXX([11])
|
||||
AC_DEFUN([_MY_CXX_CHECK_CXX_VER],
|
||||
[# _MY_CXX_CHECK_CXX_VER(flag) -- Check if compiler runs C++11
|
||||
# Set $_my_result
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([#include <thread>
|
||||
#if (__cplusplus < 201103L)
|
||||
# error "Too old"
|
||||
#endif
|
||||
], [[ ]])],
|
||||
[_my_result=yes
|
||||
if test -s conftest.err; then
|
||||
if grep -e "$1" conftest.err >/dev/null; then
|
||||
@@ -406,24 +412,24 @@ AC_LINK_IFELSE(
|
||||
fi
|
||||
fi],
|
||||
[_my_result=no])
|
||||
CFG_WITH_THREADED=$_my_result
|
||||
AC_SUBST(CFG_WITH_THREADED)
|
||||
AC_MSG_RESULT($CFG_WITH_THREADED)
|
||||
])
|
||||
|
||||
# Check compiler flag
|
||||
if test "$CFG_WITH_THREADED" = "no" ; then
|
||||
if test "$CFG_WITH_PREC11" = "no" ; then
|
||||
AC_MSG_NOTICE([[]])
|
||||
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
|
||||
AC_MSG_CHECKING(whether $CXX supports C++11)
|
||||
_MY_CXX_CHECK_CXX_VER()
|
||||
AC_MSG_RESULT($_my_result)
|
||||
if test "$_my_result" = "no" ; then
|
||||
CXXFLAGS="$CXXFLAGS $CFG_CXXFLAGS_STD_NEWEST"
|
||||
CFG_CXX_FLAGS_CMAKE="$CFG_CXX_FLAGS_CMAKE $CFG_CXXFLAGS_STD_NEWEST"
|
||||
AC_MSG_CHECKING(whether $CXX supports C++11 with $CFG_CXXFLAGS_STD_NEWEST)
|
||||
_MY_CXX_CHECK_CXX_VER()
|
||||
AC_MSG_RESULT($_my_result)
|
||||
fi
|
||||
if test "$_my_result" = "no" ; then
|
||||
AC_MSG_NOTICE([[]])
|
||||
AC_MSG_ERROR([[the $CXX compiler appears to not support C++11.
|
||||
|
||||
Verilator plans to require a C++11 or newer compiler in a future release,
|
||||
unless sufficient people report problems. Therefore, if you do not have a
|
||||
C++11 compiler, please post a message to
|
||||
https://www.veripool.org/boards/3/topics/2580-Verilator-Requiring-C-11-compiler
|
||||
indicating your OS and when you think C++11 might be ok, and then rerun
|
||||
configure with the --enable-prec11 argument. Thanks.]])
|
||||
Verilator requires a C++11 or newer compiler.]])
|
||||
|
||||
fi
|
||||
fi
|
||||
|
||||
# Checks for library functions.
|
||||
@@ -431,6 +437,24 @@ AC_CHECK_MEMBER([struct stat.st_mtim.tv_nsec],
|
||||
[AC_DEFINE([HAVE_STAT_NSEC],[1],[Defined if struct stat has st_mtim.tv_nsec])],
|
||||
[], [#include <sys/stat.h>])
|
||||
|
||||
# HAVE_SYSTEMC
|
||||
# - If found the default search path has it, so support is always enabled.
|
||||
# - If not found or not system-wide, user can set SYSTEMC_INCLUDE.
|
||||
# AC_CHECK_HEADERS seems to not locate on Travis-CI but include does work.
|
||||
AC_MSG_CHECKING([whether SystemC is found (in system path)])
|
||||
ACO_SAVE_LIBS="$LIBS"
|
||||
LIBS="$LIBS -lsystemc"
|
||||
AC_LINK_IFELSE(
|
||||
[AC_LANG_PROGRAM([[#include <systemc.h>
|
||||
extern "C" int sc_main(int argc, char* argv[]) {}
|
||||
]],[[sc_version()]])],
|
||||
[_my_result=yes
|
||||
AC_DEFINE([HAVE_SYSTEMC],[1],[Defined if have SystemC library])],
|
||||
[_my_result=no])
|
||||
AC_MSG_RESULT($_my_result)
|
||||
LIBS="$ACO_SAVE_LIBS"
|
||||
AC_SUBST(HAVE_SYSTEMC)
|
||||
|
||||
# Checks for system services
|
||||
|
||||
# Other install directories
|
||||
|
||||
+38
-4
@@ -1,44 +1,78 @@
|
||||
The contributors listed below have certified their Verilator contributions
|
||||
under the Developer Certificate of Origin
|
||||
(https://developercertificate.org/).
|
||||
under the Developer Certificate of Origin (https://developercertificate.org/).
|
||||
|
||||
Please see the Verilator manual for 200+ additional contributors. Thanks to
|
||||
all.
|
||||
Please see the Verilator manual for 200+ additional contributors. Thanks to all.
|
||||
|
||||
Ahmed El-Mahmoudy
|
||||
Alex Chadwick
|
||||
Chris Randall
|
||||
Conor McCullough
|
||||
Dan Petrisko
|
||||
David Horton
|
||||
David Stanford
|
||||
Driss Hafdi
|
||||
Edgar E. Iglesias
|
||||
Eric Rippey
|
||||
Fan Shupei
|
||||
Garrett Smith
|
||||
Geza Lore
|
||||
Gianfranco Costamagna
|
||||
Glen Gibb
|
||||
Harald Heckmann
|
||||
Howard Su
|
||||
Huang Rui
|
||||
Iztok Jeras
|
||||
James Hanlon
|
||||
James Hutchinson
|
||||
Jamey Hicks
|
||||
James Pallister
|
||||
Jan Van Winkel
|
||||
Jeremy Bennett
|
||||
John Coiner
|
||||
John Demme
|
||||
Josh Redford
|
||||
Julien Margetts
|
||||
Kanad Kanhere
|
||||
Kevin Kiningham
|
||||
Kuba Ober
|
||||
Ludwig Rogiers
|
||||
Lukasz Dalek
|
||||
Maarten De Braekeleer
|
||||
Maciej Sobkowski
|
||||
Marco Widmer
|
||||
Markus Krause
|
||||
Marshal Qiao
|
||||
Matthew Ballance
|
||||
Michael Killough
|
||||
Mike Popoloski
|
||||
Nathan Kohagen
|
||||
Nathan Myers
|
||||
Patrick Stewart
|
||||
Peter Horvath
|
||||
Peter Monsson
|
||||
Philipp Wagner
|
||||
Pieter Kapsenberg
|
||||
Piotr Binkowski
|
||||
Qingyao Sun
|
||||
Rafal Kapuscik
|
||||
Richard Myers
|
||||
Rupert Swarbrick
|
||||
Sean Cross
|
||||
Sebastien Van Cauwenberghe
|
||||
Sergi Granell
|
||||
Stefan Wallentowitz
|
||||
Stephen Henry
|
||||
Tim Snyder
|
||||
Tobias Rosenkranz
|
||||
Tobias Wölfel
|
||||
Todd Strader
|
||||
Tomasz Gorochowik
|
||||
Tymoteusz Blazejczyk
|
||||
Victor Besyakov
|
||||
Vassilis Papaefstathiou
|
||||
Veripool API Bot
|
||||
Wilson Snyder
|
||||
Yossi Nivin
|
||||
Yuri Victorovich
|
||||
Yutetsu TAKATSUKASA
|
||||
Yves Mathieu
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
clang-format is used to standardize the indentation of the internal C++
|
||||
code.
|
||||
|
||||
For the most part clang-format changes provide good consistency, the two
|
||||
main exceptions being the indentation of preprocessor directives, and
|
||||
tables of statements.
|
||||
|
||||
Reformatting is generally performed only before other large changes are to
|
||||
be made to a file. The following files are not yet clang-format clean:
|
||||
|
||||
clang-format -i include/verilated.h
|
||||
clang-format -i include/verilated_dpi.h
|
||||
clang-format -i include/verilated_fst_c.h
|
||||
clang-format -i include/verilated_heavy.h
|
||||
clang-format -i include/verilated_imp.h
|
||||
clang-format -i include/verilated_save.h
|
||||
clang-format -i include/verilated_sym_props.h
|
||||
clang-format -i include/verilated_unordered_set_map.h
|
||||
clang-format -i include/verilated_vcd_c.h
|
||||
clang-format -i include/verilatedos.h
|
||||
|
||||
clang-format -i include/verilated.cpp
|
||||
clang-format -i include/verilated_cov.cpp
|
||||
clang-format -i include/verilated_dpi.cpp
|
||||
clang-format -i include/verilated_fst_c.cpp
|
||||
clang-format -i include/verilated_save.cpp
|
||||
clang-format -i include/verilated_threads.cpp
|
||||
clang-format -i include/verilated_vcd_c.cpp
|
||||
clang-format -i include/verilated_vpi.cpp
|
||||
|
||||
clang-format -i src/V3Ast.h
|
||||
clang-format -i src/V3AstNodes.h
|
||||
clang-format -i src/V3EmitCBase.h
|
||||
clang-format -i src/V3Error.h
|
||||
clang-format -i src/V3File.h
|
||||
clang-format -i src/V3FileLine.h
|
||||
clang-format -i src/V3Global.h
|
||||
clang-format -i src/V3Graph.h
|
||||
clang-format -i src/V3GraphDfa.h
|
||||
clang-format -i src/V3GraphStream.h
|
||||
clang-format -i src/V3Hashed.h
|
||||
clang-format -i src/V3LanguageWords.h
|
||||
clang-format -i src/V3LinkDot.h
|
||||
clang-format -i src/V3List.h
|
||||
clang-format -i src/V3Number.h
|
||||
clang-format -i src/V3Options.h
|
||||
clang-format -i src/V3OrderGraph.h
|
||||
clang-format -i src/V3Os.h
|
||||
clang-format -i src/V3ParseImp.h
|
||||
clang-format -i src/V3ParseSym.h
|
||||
clang-format -i src/V3Partition.h
|
||||
clang-format -i src/V3PartitionGraph.h
|
||||
clang-format -i src/V3PreLex.h
|
||||
clang-format -i src/V3PreProc.h
|
||||
clang-format -i src/V3Scoreboard.h
|
||||
clang-format -i src/V3SenTree.h
|
||||
clang-format -i src/V3Simulate.h
|
||||
clang-format -i src/V3Stats.h
|
||||
clang-format -i src/V3String.h
|
||||
clang-format -i src/V3SymTable.h
|
||||
clang-format -i src/V3TSP.h
|
||||
clang-format -i src/V3Task.h
|
||||
clang-format -i src/V3WidthCommit.h
|
||||
|
||||
clang-format -i src/V3Active.cpp
|
||||
clang-format -i src/V3ActiveTop.cpp
|
||||
clang-format -i src/V3Assert.cpp
|
||||
clang-format -i src/V3AssertPre.cpp
|
||||
clang-format -i src/V3Ast.cpp
|
||||
clang-format -i src/V3AstNodes.cpp
|
||||
clang-format -i src/V3Begin.cpp
|
||||
clang-format -i src/V3Branch.cpp
|
||||
clang-format -i src/V3Broken.cpp
|
||||
clang-format -i src/V3CCtors.cpp
|
||||
clang-format -i src/V3Case.cpp
|
||||
clang-format -i src/V3Cast.cpp
|
||||
clang-format -i src/V3Cdc.cpp
|
||||
clang-format -i src/V3Changed.cpp
|
||||
clang-format -i src/V3Clean.cpp
|
||||
clang-format -i src/V3Clock.cpp
|
||||
clang-format -i src/V3Combine.cpp
|
||||
clang-format -i src/V3Const.cpp
|
||||
clang-format -i src/V3Coverage.cpp
|
||||
clang-format -i src/V3CoverageJoin.cpp
|
||||
clang-format -i src/V3Dead.cpp
|
||||
clang-format -i src/V3Delayed.cpp
|
||||
clang-format -i src/V3Depth.cpp
|
||||
clang-format -i src/V3DepthBlock.cpp
|
||||
clang-format -i src/V3EmitC.cpp
|
||||
clang-format -i src/V3EmitCInlines.cpp
|
||||
clang-format -i src/V3EmitCMake.cpp
|
||||
clang-format -i src/V3EmitCSyms.cpp
|
||||
clang-format -i src/V3EmitMk.cpp
|
||||
clang-format -i src/V3EmitV.cpp
|
||||
clang-format -i src/V3EmitXml.cpp
|
||||
clang-format -i src/V3Error.cpp
|
||||
clang-format -i src/V3Expand.cpp
|
||||
clang-format -i src/V3File.cpp
|
||||
clang-format -i src/V3FileLine.cpp
|
||||
clang-format -i src/V3Gate.cpp
|
||||
clang-format -i src/V3GenClk.cpp
|
||||
clang-format -i src/V3Graph.cpp
|
||||
clang-format -i src/V3GraphAcyc.cpp
|
||||
clang-format -i src/V3GraphAlg.cpp
|
||||
clang-format -i src/V3GraphDfa.cpp
|
||||
clang-format -i src/V3GraphPathChecker.cpp
|
||||
clang-format -i src/V3GraphTest.cpp
|
||||
clang-format -i src/V3Hashed.cpp
|
||||
clang-format -i src/V3Inline.cpp
|
||||
clang-format -i src/V3Inst.cpp
|
||||
clang-format -i src/V3InstrCount.cpp
|
||||
clang-format -i src/V3Life.cpp
|
||||
clang-format -i src/V3LifePost.cpp
|
||||
clang-format -i src/V3LinkCells.cpp
|
||||
clang-format -i src/V3LinkDot.cpp
|
||||
clang-format -i src/V3LinkJump.cpp
|
||||
clang-format -i src/V3LinkLValue.cpp
|
||||
clang-format -i src/V3LinkLevel.cpp
|
||||
clang-format -i src/V3LinkParse.cpp
|
||||
clang-format -i src/V3LinkResolve.cpp
|
||||
clang-format -i src/V3Localize.cpp
|
||||
clang-format -i src/V3Name.cpp
|
||||
clang-format -i src/V3Number.cpp
|
||||
clang-format -i src/V3Number_test.cpp
|
||||
clang-format -i src/V3Options.cpp
|
||||
clang-format -i src/V3Order.cpp
|
||||
clang-format -i src/V3Os.cpp
|
||||
clang-format -i src/V3Param.cpp
|
||||
clang-format -i src/V3ParseGrammar.cpp
|
||||
clang-format -i src/V3ParseImp.cpp
|
||||
clang-format -i src/V3ParseLex.cpp
|
||||
clang-format -i src/V3Partition.cpp
|
||||
clang-format -i src/V3PreProc.cpp
|
||||
clang-format -i src/V3PreShell.cpp
|
||||
clang-format -i src/V3Premit.cpp
|
||||
clang-format -i src/V3ProtectLib.cpp
|
||||
clang-format -i src/V3Reloop.cpp
|
||||
clang-format -i src/V3Scope.cpp
|
||||
clang-format -i src/V3Scoreboard.cpp
|
||||
clang-format -i src/V3Slice.cpp
|
||||
clang-format -i src/V3Split.cpp
|
||||
clang-format -i src/V3SplitAs.cpp
|
||||
clang-format -i src/V3SplitVar.cpp
|
||||
clang-format -i src/V3Stats.cpp
|
||||
clang-format -i src/V3StatsReport.cpp
|
||||
clang-format -i src/V3String.cpp
|
||||
clang-format -i src/V3Subst.cpp
|
||||
clang-format -i src/V3TSP.cpp
|
||||
clang-format -i src/V3Table.cpp
|
||||
clang-format -i src/V3Task.cpp
|
||||
clang-format -i src/V3Trace.cpp
|
||||
clang-format -i src/V3TraceDecl.cpp
|
||||
clang-format -i src/V3Tristate.cpp
|
||||
clang-format -i src/V3Undriven.cpp
|
||||
clang-format -i src/V3Unknown.cpp
|
||||
clang-format -i src/V3Unroll.cpp
|
||||
clang-format -i src/V3Width.cpp
|
||||
clang-format -i src/V3WidthSel.cpp
|
||||
clang-format -i src/Verilator.cpp
|
||||
+26
-27
@@ -39,7 +39,7 @@ brief:
|
||||
#sudo apt-get install libfl2 # Ubuntu only (ignore if gives error)
|
||||
#sudo apt-get install libfl-dev # Ubuntu only (ignore if gives error)
|
||||
|
||||
git clone https://git.veripool.org/git/verilator # Only first time
|
||||
git clone https://github.com/verilator/verilator # Only first time
|
||||
## Note the URL above is not a page you can see with a browser, it's for git only
|
||||
|
||||
# Every time you need to build:
|
||||
@@ -69,36 +69,36 @@ Linux distribution, see instead <<Install From a Package Manager>>.
|
||||
|
||||
=== OS Requirements
|
||||
|
||||
Verilator is developed and has primary testing on Ubuntu. Versions have
|
||||
also built on Redhat Linux, Apple OS-X, HPUX and Solaris. It should run
|
||||
with minor porting on any GNU/Linux-ish platform. Verilator also works on
|
||||
Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
|
||||
output (not Verilator itself) compiles under all the options above, plus
|
||||
MSVC++.
|
||||
Verilator is developed and has primary testing on Ubuntu, with additional
|
||||
testing on FreeBSD and Apple OS-X. Versions have also built on Redhat
|
||||
Linux, HPUX and Solaris. It should run with minor porting on any
|
||||
GNU/Linux-ish platform. Verilator also works on Windows under Cygwin, and
|
||||
Windows under MinGW (gcc -mno-cygwin). Verilated output (not Verilator
|
||||
itself) compiles under all the options above, plus MSVC++.
|
||||
|
||||
=== Install Prerequisites
|
||||
|
||||
To build Verilator you will need to install some standard packages:
|
||||
To build or run Verilator you need these standard packages:
|
||||
|
||||
sudo apt-get install git
|
||||
sudo apt-get install autoconf
|
||||
sudo apt-get install flex bison
|
||||
|
||||
The following are optional, but improve compilation speed:
|
||||
|
||||
sudo apt-get install libgoogle-perftools-dev
|
||||
|
||||
Additionally, to build or run Verilator you need these standard packages:
|
||||
|
||||
sudo apt-get install perl python3
|
||||
sudo apt-get install make
|
||||
sudo apt-get install perl python3 make
|
||||
sudo apt-get install g++ # Alternatively, clang
|
||||
sudo apt-get install libgz # Non-Ubuntu (ignore if gives error)
|
||||
sudo apt-get install libfl2 libfl-dev zlibc zlib1g zlib1g-dev # Ubuntu only (ignore if gives error)
|
||||
|
||||
Those developing Verilator may also want these (see internals.adoc):
|
||||
To build or run the following are optional but should be installed for
|
||||
good performance:
|
||||
|
||||
sudo apt-get install gdb asciidoctor graphviz cmake
|
||||
sudo apt-get install ccache # If present at build, needed for run
|
||||
sudo apt-get install libgoogle-perftools-dev numactl perl-doc
|
||||
|
||||
To build Verilator you will need to install these packages; these do not
|
||||
need to be present to run Verilator:
|
||||
|
||||
sudo apt-get install git autoconf flex bison
|
||||
|
||||
Those developing Verilator itself may also want these (see internals.adoc):
|
||||
|
||||
sudo apt-get install gdb asciidoctor graphviz cmake clang clang-format gprof lcov
|
||||
cpan install Pod::Perldoc
|
||||
cpan install Unix::Processors
|
||||
cpan install Parallel::Forker
|
||||
@@ -128,7 +128,7 @@ Downloads]; we presume you know how to use it, and is not described here.)
|
||||
|
||||
Get the sources from the repository: (You need do this only once, ever.)
|
||||
|
||||
git clone https://git.veripool.org/git/verilator # Only first time
|
||||
git clone https://github.com/verilator/verilator # Only first time
|
||||
## Note the URL above is not a page you can see with a browser, it's for git only
|
||||
|
||||
Enter the checkout and determine what version/branch to use:
|
||||
@@ -264,10 +264,9 @@ set in your environment; it is built into the executable.
|
||||
|
||||
== Announcements
|
||||
|
||||
To get notified of new releases, login to
|
||||
https://www.veripool.org[Veripool], and click the "watch" button near the
|
||||
top right under https://www.veripool.org/projects/verilator/news[Verilator
|
||||
News].
|
||||
To get notified of new releases, go to
|
||||
https://github.com/verilator/verilator-announce[Verilator announcement
|
||||
repository] and follow the instructions there.
|
||||
|
||||
== Directory Structure
|
||||
|
||||
|
||||
+54
-21
@@ -387,10 +387,8 @@ changed; if clear, checking those signals for changes may be skipped.
|
||||
|
||||
=== Compiler Version and C++11
|
||||
|
||||
Verilator supports GCC 4.4.7 and newer. GCC 4.4.7 does not support C++11,
|
||||
therefore C++11 is generally not required. Exceptions may be made to
|
||||
require C++11 for features that are only practical with C++11,
|
||||
e.g. threads.
|
||||
Verilator requires C++11. Verilator does not require any newer versions,
|
||||
but is maintained to build successfully with C++14/C++17/C++20.
|
||||
|
||||
=== Indentation and Naming Style
|
||||
|
||||
@@ -405,6 +403,15 @@ This sets indentation to the `cc-mode` defaults. (Verilator predates a
|
||||
CC-mode change of several years ago which overrides the defaults with GNU
|
||||
style indentation; the `c-set-style` undoes that.)
|
||||
|
||||
* Use "mixedCapsSymbols" instead of "underlined_symbols".
|
||||
|
||||
* Uas a "p" suffix on variables that are pointers, e.g. "nodep".
|
||||
|
||||
* Comment every member variable.
|
||||
|
||||
Indentation is automatically maintained with "make clang-format" (using
|
||||
clang-format version 10.0.0). For those manually formatting:
|
||||
|
||||
* Use 4 spaces per level, and no tabs.
|
||||
|
||||
* Use 2 spaces between the end of source and the beginning of a comment.
|
||||
@@ -414,12 +421,6 @@ style indentation; the `c-set-style` undoes that.)
|
||||
* No spaces before semicolons, nor between a function's name and open
|
||||
parenthesis (only applies to functions; if/else has a following space).
|
||||
|
||||
* Use "mixedCapsSymbols" instead of "underlined_symbols".
|
||||
|
||||
* Uas a "p" suffix on variables that are pointers, e.g. "nodep".
|
||||
|
||||
* Comment every member variable.
|
||||
|
||||
=== The `astgen` Script
|
||||
|
||||
Some of the code implementing passes is extremely repetitive, and must be
|
||||
@@ -585,7 +586,7 @@ dealing with. For example a visitor might not implement separate `visit`
|
||||
methods for `AstIf` and `AstGenIf`, but just a single method for the base
|
||||
class:
|
||||
|
||||
void visit (AstNodeIf* nodep)
|
||||
void visit(AstNodeIf* nodep)
|
||||
|
||||
However that method might want to specify additional code if it is called
|
||||
for `AstGenIf`. Verilator does this by providing a `VN_IS` method for each
|
||||
@@ -671,7 +672,7 @@ Set to 1 to indicate that the compilation or execution is intended to fail.
|
||||
For example the following would specify that compilation requires two
|
||||
defines and is expected to fail.
|
||||
|
||||
compile (
|
||||
compile(
|
||||
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
|
||||
fails => 1,
|
||||
);
|
||||
@@ -757,6 +758,15 @@ may be required to setup the system for fuzzing.
|
||||
|
||||
== Debugging
|
||||
|
||||
=== Debug Levels
|
||||
|
||||
The "UINFO" calls in the source indicate a debug level. Messages level 3
|
||||
and below are globally enabled with `--debug`. Higher levels may be
|
||||
controlled with `--debugi <level>`. An individual source file levels may
|
||||
be controlled with `-debugi-<srcfile> <level>`. For example `--debug
|
||||
--debugi 5 --debugi-V3Width 9` will use the debug binary at default debug
|
||||
level 5, with the V3Width.cpp file at level 9.
|
||||
|
||||
=== --debug
|
||||
|
||||
When you run with `--debug` there are two primary output file types placed
|
||||
@@ -774,19 +784,20 @@ output, for example:
|
||||
You can then print a.ps. You may prefer gif format, which doesn't get
|
||||
scaled so can be more useful with large graphs.
|
||||
|
||||
For dynamic graph viewing consider
|
||||
For interactive graph viewing consider
|
||||
https://github.com/jrfonseca/xdot.py[xdot] or
|
||||
http://zvtm.sourceforge.net/zgrviewer.html[ZGRViewer]. If you know of
|
||||
better viewers let us know; ZGRViewer isn't great for large graphs.
|
||||
better viewers (especially for large graphs) please let us know.
|
||||
|
||||
=== .tree Output
|
||||
|
||||
Tree files are dumps of the AST Tree and are produced between every major
|
||||
algorithmic stage. An example:
|
||||
|
||||
NETLIST 0x90fb00 <e1> {a0}
|
||||
1: MODULE 0x912b20 <e8822> {a8} top L2 [P]
|
||||
*1:2: VAR 0x91a780 <e74#> {a22} @dt=0xa2e640(w32) out_wide [O] WIRE
|
||||
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24} @dt=this(sw32) integer kwd=integer range=[31:0]
|
||||
NETLIST 0x90fb00 <e1> {a0ah}
|
||||
1: MODULE 0x912b20 <e8822> {a8ah} top L2 [P]
|
||||
*1:2: VAR 0x91a780 <e74#> {a22ah} @dt=0xa2e640(w32) out_wide [O] WIRE
|
||||
1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24ah} @dt=this(sw32) integer kwd=integer range=[31:0]
|
||||
|
||||
The following summarizes the above example dump, with more detail on each
|
||||
field in the section below.
|
||||
@@ -804,8 +815,9 @@ the `MODULE`, which in turn is the `op1p` pointer under the `NETLIST`
|
||||
| `<e74>` | means the 74th edit to the netlist was the last modification to
|
||||
this node.
|
||||
|
||||
| `{a22}` | indicates this node is related to line 22 in the source filename
|
||||
"a", where "a" is the first file read, "z" the 26th, and "aa" the 27th.
|
||||
| `{a22ah}` | indicates this node is related to the source filename "a",
|
||||
where "a" is the first file read, "z" the 26th, and "aa" the 27th. Then
|
||||
line 22 in that file, then column 8 (aa=0, az=25, ba=26, ...).
|
||||
|
||||
| `@dt=0x...` | indicates the address of the data type this node contains.
|
||||
|
||||
@@ -846,7 +858,10 @@ correspond directly to Verilog entities (for example `MODULE` and
|
||||
Address of the node::
|
||||
|
||||
A hexadecimal address of the node in memory. Useful for examining with the
|
||||
debugger.
|
||||
debugger. If the actual address values are not important, then using the
|
||||
`--dump-tree-addrids` option will convert address values to short identifiers
|
||||
of the form `([A-Z]*)`, which is hopefully easier for the reader to cross
|
||||
reference throughout the dump.
|
||||
|
||||
Last edit number::
|
||||
|
||||
@@ -993,6 +1008,24 @@ function in `src/verilator.cpp`.
|
||||
To get your pass to build you'll need to add its binary filename to the
|
||||
list in `src/Makefile_obj.in` and reconfigure.
|
||||
|
||||
=== "Never" features
|
||||
|
||||
Verilator ideally would support all of IEEE, and has the goal to get close
|
||||
to full support. However the following IEEE sections and features are not
|
||||
anticipated to be ever implemented for the reasons indicated.
|
||||
|
||||
[horizontal]
|
||||
IEEE 1800-2017 3.3 recursive modules:: Little/no tool support, and arguably not a good practice.
|
||||
IEEE 1800-2017 6.12 "shortreal":: Little/no tool support, and easily simply promoted to real.
|
||||
IEEE 1800-2017 11.11 Min, typ, max:: No SDF support so will always use typical.
|
||||
IEEE 1800-2017 11.12 "let":: Little/no tool support, makes difficult to implement parsers.
|
||||
IEEE 1800-2017 20.15 Probabilistic functions:: Little industry use.
|
||||
IEEE 1800-2017 20.16 Stochastic analysis:: Little industry use.
|
||||
IEEE 1800-2017 20.17 PLA modeling:: Little industry use and outdated technology.
|
||||
IEEE 1800-2017 31 Timing checks:: No longer relevant with static timing analysis tools.
|
||||
IEEE 1800-2017 32 SDF annotation:: No longer relevant with static timing analysis tools.
|
||||
IEEE 1800-2017 33 Config:: Little/no tool support or industry use.
|
||||
|
||||
== Distribution
|
||||
|
||||
Copyright 2008-2020 by Wilson Snyder. Verilator is free software; you can
|
||||
|
||||
+1
-1
@@ -21,7 +21,7 @@ parser.
|
||||
|
||||
== Structure
|
||||
|
||||
The XML document is consists of 4 sections within the top level `verilator_xml`
|
||||
The XML document consists of 4 sections within the top level `verilator_xml`
|
||||
element:
|
||||
|
||||
`<files>`...`</files>`::
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This is an example cmake script to build a verilog to systemc project
|
||||
# using cmake and verilator.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
# This makefile is here for testing the examples and should
|
||||
# generally not be added to a CMake project.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
@@ -51,11 +49,11 @@ run:
|
||||
@echo "-- Verilator CMake hello world example"
|
||||
|
||||
@echo
|
||||
@echo "-- CMake ----------------"
|
||||
@echo "-- VERILATE ----------------"
|
||||
mkdir -p build && cd build && cmake ..
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE -----------------"
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
|
||||
@echo
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This is an example cmake script to build a verilog to SystemC project
|
||||
# using CMake and Verilator.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
# This makefile is here for testing the examples and should
|
||||
# generally not be added to a CMake project.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
@@ -87,11 +85,11 @@ run:
|
||||
@echo "-- Verilator CMake SystemC hello-world simple example"
|
||||
|
||||
@echo
|
||||
@echo "-- CMake ----------------"
|
||||
@echo "-- VERILATE ----------------"
|
||||
mkdir -p build && cd build && cmake ..
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE -----------------"
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
|
||||
@echo
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This is an example cmake script to build a verilog to systemc project
|
||||
# using cmake and verilator.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
# This makefile is here for testing the examples and should
|
||||
# generally not be added to a CMake project.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
@@ -51,11 +49,11 @@ run:
|
||||
@echo "-- Verilator CMake protect_lib example"
|
||||
|
||||
@echo
|
||||
@echo "-- CMake ----------------"
|
||||
@echo "-- VERILATE ----------------"
|
||||
mkdir -p build && cd build && cmake ..
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE -----------------"
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
|
||||
@echo
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This is an example cmake script to build a verilog to systemc project
|
||||
# using cmake and verilator.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
# This makefile is here for testing the examples and should
|
||||
# generally not be added to a CMake project.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
@@ -51,11 +49,11 @@ run:
|
||||
@echo "-- Verilator CMake tracing example"
|
||||
|
||||
@echo
|
||||
@echo "-- CMake ----------------"
|
||||
@echo "-- VERILATE ----------------"
|
||||
mkdir -p build && cd build && cmake ..
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE -----------------"
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
|
||||
@echo
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This is an example cmake script to build a verilog to SystemC project
|
||||
# using CMake and Verilator.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
# This makefile is here for testing the examples and should
|
||||
# generally not be added to a CMake project.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
@@ -87,11 +85,11 @@ run:
|
||||
@echo "-- Verilator CMake SystemC tracing example"
|
||||
|
||||
@echo
|
||||
@echo "-- CMake ----------------"
|
||||
@echo "-- VERILATE ----------------"
|
||||
mkdir -p build && cd build && cmake ..
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE -----------------"
|
||||
@echo "-- BUILD -------------------"
|
||||
cmake --build build
|
||||
|
||||
@echo
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
@@ -36,10 +34,8 @@ endif
|
||||
|
||||
default:
|
||||
@echo "-- Verilator hello-world simple example"
|
||||
@echo "-- VERILATE ----------------"
|
||||
$(VERILATOR) -cc --exe top.v sim_main.cpp
|
||||
@echo "-- COMPILE -----------------"
|
||||
$(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
@echo "-- VERILATE & BUILD --------"
|
||||
$(VERILATOR) -cc --exe --build -j top.v sim_main.cpp
|
||||
@echo "-- RUN ---------------------"
|
||||
obj_dir/Vtop
|
||||
@echo "-- DONE --------------------"
|
||||
|
||||
@@ -19,7 +19,7 @@ int main(int argc, char** argv, char** env) {
|
||||
// e.g. examples/c_tracing.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv && env) {}
|
||||
if (false && argc && argv && env) {}
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||
Vtop* top = new Vtop;
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
@@ -45,10 +43,8 @@ endif
|
||||
|
||||
run:
|
||||
@echo "-- Verilator hello-world simple example"
|
||||
@echo "-- VERILATE ----------------"
|
||||
$(VERILATOR) -sc --exe top.v sc_main.cpp
|
||||
@echo "-- COMPILE -----------------"
|
||||
$(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
@echo "-- VERILATE & COMPILE ------"
|
||||
$(VERILATOR) -sc --exe --build -j top.v sc_main.cpp
|
||||
@echo "-- RUN ---------------------"
|
||||
obj_dir/Vtop
|
||||
@echo "-- DONE --------------------"
|
||||
|
||||
@@ -23,25 +23,17 @@ int sc_main(int argc, char* argv[]) {
|
||||
// e.g. examples/c_tracing.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv) {}
|
||||
if (false && argc && argv) {}
|
||||
|
||||
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
|
||||
Vtop* top = new Vtop("top");
|
||||
|
||||
// Initialize SC model
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_start(1,SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
sc_start(1, SC_NS);
|
||||
|
||||
// Simulate until $finish
|
||||
while (!Verilated::gotFinish()) {
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_start(1,SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
sc_start(1, SC_NS);
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This calls the object directory makefiles. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2019 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
|
||||
# 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
|
||||
@@ -70,7 +68,7 @@ run:
|
||||
@echo " library (libverilated_secret.a) generated from the previous"
|
||||
@echo " step"
|
||||
@echo "---------------------------------------------------------------"
|
||||
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '-L../obj_dir_secret -lverilated_secret -static' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
|
||||
$(VERILATOR) $(TOP_VERILATOR_FLAGS) --exe -LDFLAGS '../obj_dir_secret/libverilated_secret.a' top.v obj_dir_secret/verilated_secret.sv sim_main.cpp
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE entire design --------------------------------------"
|
||||
|
||||
@@ -6,14 +6,16 @@
|
||||
|
||||
// This module will be used as libsecret.a or libsecret.so without
|
||||
// exposing the source.
|
||||
module secret_impl(
|
||||
input [31:0] a,
|
||||
input [31:0] b,
|
||||
output logic [31:0] x,
|
||||
input clk);
|
||||
|
||||
logic [31:0] accum_q = 0;
|
||||
logic [31:0] secret_value = 9;
|
||||
module secret_impl
|
||||
(
|
||||
input [31:0] a,
|
||||
input [31:0] b,
|
||||
output logic [31:0] x,
|
||||
input clk);
|
||||
|
||||
logic [31:0] accum_q = 0;
|
||||
logic [31:0] secret_value = 9;
|
||||
|
||||
initial $display("%m: initialized");
|
||||
|
||||
|
||||
@@ -17,12 +17,10 @@
|
||||
#endif
|
||||
|
||||
vluint64_t main_time = 0;
|
||||
double sc_time_stamp() {
|
||||
return main_time;
|
||||
}
|
||||
double sc_time_stamp() { return main_time; }
|
||||
|
||||
int main(int argc, char** argv, char** env) {
|
||||
if (0 && argc && argv && env) {}
|
||||
if (false && argc && argv && env) {}
|
||||
|
||||
Verilated::debug(0);
|
||||
Verilated::randReset(2);
|
||||
@@ -33,9 +31,9 @@ int main(int argc, char** argv, char** env) {
|
||||
|
||||
#if VM_TRACE
|
||||
// When tracing, the contents of the secret module will not be seen
|
||||
VerilatedVcdC* tfp = NULL;
|
||||
VerilatedVcdC* tfp = nullptr;
|
||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||
if (flag && 0==strcmp(flag, "+trace")) {
|
||||
if (flag && 0 == strcmp(flag, "+trace")) {
|
||||
Verilated::traceEverOn(true);
|
||||
VL_PRINTF("Enabling waves into logs/vlt_dump.vcd...\n");
|
||||
tfp = new VerilatedVcdC;
|
||||
@@ -62,11 +60,15 @@ int main(int argc, char** argv, char** env) {
|
||||
|
||||
// Close trace if opened
|
||||
#if VM_TRACE
|
||||
if (tfp) { tfp->close(); tfp = NULL; }
|
||||
if (tfp) {
|
||||
tfp->close();
|
||||
tfp = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Destroy model
|
||||
delete top; top = NULL;
|
||||
delete top;
|
||||
top = nullptr;
|
||||
|
||||
// Fin
|
||||
exit(0);
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
@@ -68,11 +66,13 @@ run:
|
||||
$(VERILATOR) $(VERILATOR_FLAGS) $(VERILATOR_INPUT)
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE -----------------"
|
||||
# To compile, we can either just do what Verilator asks,
|
||||
# or call a submakefile where we can override the rules ourselves
|
||||
# $(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
$(MAKE) -j 4 -C obj_dir -f ../Makefile_obj
|
||||
@echo "-- BUILD -------------------"
|
||||
# To compile, we can either
|
||||
# 1. Pass --build to Verilator by editing VERILATOR_FLAGS above.
|
||||
# 2. Or, run the make rules Verilator does:
|
||||
# $(MAKE) -j -C obj_dir -f Vtop.mk
|
||||
# 3. Or, call a submakefile where we can override the rules ourselves:
|
||||
$(MAKE) -j -C obj_dir -f ../Makefile_obj
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
#
|
||||
# This is executed in the object directory, and called by ../Makefile
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ int main(int argc, char** argv, char** env) {
|
||||
// This is a more complicated example, please also see the simpler examples/make_hello_c.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv && env) {}
|
||||
if (false && argc && argv && env) {}
|
||||
|
||||
// Set debug level, 0 is off, 9 is highest presently used
|
||||
// May be overridden by commandArgs
|
||||
@@ -83,9 +83,9 @@ int main(int argc, char** argv, char** env) {
|
||||
|
||||
// Read outputs
|
||||
VL_PRINTF("[%" VL_PRI64 "d] clk=%x rstl=%x iquad=%" VL_PRI64 "x"
|
||||
" -> oquad=%" VL_PRI64"x owide=%x_%08x_%08x\n",
|
||||
main_time, top->clk, top->reset_l, top->in_quad,
|
||||
top->out_quad, top->out_wide[2], top->out_wide[1], top->out_wide[0]);
|
||||
" -> oquad=%" VL_PRI64 "x owide=%x_%08x_%08x\n",
|
||||
main_time, top->clk, top->reset_l, top->in_quad, top->out_quad, top->out_wide[2],
|
||||
top->out_wide[1], top->out_wide[0]);
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
@@ -98,7 +98,8 @@ int main(int argc, char** argv, char** env) {
|
||||
#endif
|
||||
|
||||
// Destroy model
|
||||
delete top; top = NULL;
|
||||
delete top;
|
||||
top = nullptr;
|
||||
|
||||
// Fin
|
||||
exit(0);
|
||||
|
||||
@@ -11,15 +11,15 @@
|
||||
module top
|
||||
(
|
||||
// Declare some signals so we can see how I/O works
|
||||
input clk,
|
||||
input reset_l,
|
||||
input clk,
|
||||
input reset_l,
|
||||
|
||||
output wire [1:0] out_small,
|
||||
output wire [39:0] out_quad,
|
||||
output wire [69:0] out_wide,
|
||||
input [1:0] in_small,
|
||||
input [39:0] in_quad,
|
||||
input [69:0] in_wide
|
||||
input [1:0] in_small,
|
||||
input [39:0] in_quad,
|
||||
input [69:0] in_wide
|
||||
);
|
||||
|
||||
// Connect up the outputs, using some trivial logic
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
# This calls the object directory makefile. That allows the objects to
|
||||
# be placed in the "current directory" which simplifies the Makefile.
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
@@ -77,10 +75,12 @@ run:
|
||||
|
||||
@echo
|
||||
@echo "-- COMPILE -----------------"
|
||||
# To compile, we can either just do what Verilator asks,
|
||||
# or call a submakefile where we can override the rules ourselves
|
||||
# $(MAKE) -j 4 -C obj_dir -f Vtop.mk
|
||||
$(MAKE) -j 4 -C obj_dir -f ../Makefile_obj
|
||||
# To compile, we can either
|
||||
# 1. Pass --build to Verilator by editing VERILATOR_FLAGS above.
|
||||
# 2. Or, run the make rules Verilator does:
|
||||
# $(MAKE) -j -C obj_dir -f Vtop.mk
|
||||
# 3. Or, call a submakefile where we can override the rules ourselves:
|
||||
$(MAKE) -j -C obj_dir -f ../Makefile_obj
|
||||
|
||||
@echo
|
||||
@echo "-- RUN ---------------------"
|
||||
|
||||
@@ -5,11 +5,9 @@
|
||||
#
|
||||
# This is executed in the object directory, and called by ../Makefile
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
#######################################################################
|
||||
|
||||
@@ -39,8 +37,8 @@ endif
|
||||
# If you build your own rules from scratch, note you need to include
|
||||
# SystemC as follows (Vtop.mk file includes verilated.mk with these
|
||||
# already).
|
||||
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
|
||||
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
|
||||
# CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
|
||||
# LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
|
||||
|
||||
# See the benchmarking section of bin/verilator.
|
||||
# Support class optimizations. This includes the tracing and symbol table.
|
||||
|
||||
@@ -24,7 +24,7 @@ int sc_main(int argc, char* argv[]) {
|
||||
// This is a more complicated example, please also see the simpler examples/make_hello_c.
|
||||
|
||||
// Prevent unused variable warnings
|
||||
if (0 && argc && argv) {}
|
||||
if (false && argc && argv) {}
|
||||
|
||||
// Set debug level, 0 is off, 9 is highest presently used
|
||||
// May be overridden by commandArgs
|
||||
@@ -44,21 +44,9 @@ int sc_main(int argc, char* argv[]) {
|
||||
// General logfile
|
||||
ios::sync_with_stdio();
|
||||
|
||||
// Defaults time
|
||||
#if (SYSTEMC_VERSION>20011000)
|
||||
#else
|
||||
sc_time dut(1.0, sc_ns);
|
||||
sc_set_default_time_unit(dut);
|
||||
#endif
|
||||
|
||||
// Define clocks
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_clock clk ("clk", 10,SC_NS, 0.5, 3,SC_NS, true);
|
||||
sc_clock fastclk ("fastclk", 2,SC_NS, 0.5, 2,SC_NS, true);
|
||||
#else
|
||||
sc_clock clk ("clk", 10, 0.5, 3, true);
|
||||
sc_clock fastclk ("fastclk", 2, 0.5, 2, true);
|
||||
#endif
|
||||
sc_clock clk("clk", 10, SC_NS, 0.5, 3, SC_NS, true);
|
||||
sc_clock fastclk("fastclk", 2, SC_NS, 0.5, 2, SC_NS, true);
|
||||
|
||||
// Define interconnect
|
||||
sc_signal<bool> reset_l;
|
||||
@@ -72,15 +60,15 @@ int sc_main(int argc, char* argv[]) {
|
||||
// Construct the Verilated model, from inside Vtop.h
|
||||
Vtop* top = new Vtop("top");
|
||||
// Attach signals to the model
|
||||
top->clk (clk);
|
||||
top->fastclk (fastclk);
|
||||
top->reset_l (reset_l);
|
||||
top->in_small (in_small);
|
||||
top->in_quad (in_quad);
|
||||
top->in_wide (in_wide);
|
||||
top->out_small (out_small);
|
||||
top->out_quad (out_quad);
|
||||
top->out_wide (out_wide);
|
||||
top->clk(clk);
|
||||
top->fastclk(fastclk);
|
||||
top->reset_l(reset_l);
|
||||
top->in_small(in_small);
|
||||
top->in_quad(in_quad);
|
||||
top->in_wide(in_wide);
|
||||
top->out_small(out_small);
|
||||
top->out_quad(out_quad);
|
||||
top->out_wide(out_wide);
|
||||
|
||||
#if VM_TRACE
|
||||
// Before any evaluation, need to know to calculate those signals only used for tracing
|
||||
@@ -89,18 +77,14 @@ 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.
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_start(1,SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
sc_start(1, SC_NS);
|
||||
|
||||
#if VM_TRACE
|
||||
// If verilator was invoked with --trace argument,
|
||||
// and if at run time passed the +trace argument, turn on tracing
|
||||
VerilatedVcdSc* tfp = NULL;
|
||||
VerilatedVcdSc* tfp = nullptr;
|
||||
const char* flag = Verilated::commandArgsPlusMatch("trace");
|
||||
if (flag && 0==strcmp(flag, "+trace")) {
|
||||
if (flag && 0 == strcmp(flag, "+trace")) {
|
||||
cout << "Enabling waves into logs/vlt_dump.vcd...\n";
|
||||
tfp = new VerilatedVcdSc;
|
||||
top->trace(tfp, 99); // Trace 99 levels of hierarchy
|
||||
@@ -118,18 +102,14 @@ int sc_main(int argc, char* argv[]) {
|
||||
#endif
|
||||
|
||||
// Apply inputs
|
||||
if (VL_TIME_Q() > 1 && VL_TIME_Q() < 10) {
|
||||
if (sc_time_stamp() > sc_time(1, SC_NS) && sc_time_stamp() < sc_time(10, SC_NS)) {
|
||||
reset_l = !1; // Assert reset
|
||||
} else if (VL_TIME_Q() > 1) {
|
||||
} else {
|
||||
reset_l = !0; // Deassert reset
|
||||
}
|
||||
|
||||
// Simulate 1ns
|
||||
#if (SYSTEMC_VERSION>=20070314)
|
||||
sc_start(1,SC_NS);
|
||||
#else
|
||||
sc_start(1);
|
||||
#endif
|
||||
sc_start(1, SC_NS);
|
||||
}
|
||||
|
||||
// Final model cleanup
|
||||
@@ -137,7 +117,10 @@ int sc_main(int argc, char* argv[]) {
|
||||
|
||||
// Close trace if opened
|
||||
#if VM_TRACE
|
||||
if (tfp) { tfp->close(); tfp = NULL; }
|
||||
if (tfp) {
|
||||
tfp->close();
|
||||
tfp = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Coverage analysis (since test passed)
|
||||
@@ -147,7 +130,8 @@ int sc_main(int argc, char* argv[]) {
|
||||
#endif
|
||||
|
||||
// Destroy model
|
||||
delete top; top = NULL;
|
||||
delete top;
|
||||
top = nullptr;
|
||||
|
||||
// Fin
|
||||
return 0;
|
||||
|
||||
@@ -11,16 +11,16 @@
|
||||
module top
|
||||
(
|
||||
// Declare some signals so we can see how I/O works
|
||||
input clk,
|
||||
input fastclk,
|
||||
input reset_l,
|
||||
input clk,
|
||||
input fastclk,
|
||||
input reset_l,
|
||||
|
||||
output wire [1:0] out_small,
|
||||
output wire [39:0] out_quad,
|
||||
output wire [69:0] out_wide,
|
||||
input [1:0] in_small,
|
||||
input [39:0] in_quad,
|
||||
input [69:0] in_wide
|
||||
input [1:0] in_small,
|
||||
input [39:0] in_quad,
|
||||
input [69:0] in_wide
|
||||
);
|
||||
|
||||
// Connect up the outputs, using some trivial logic
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
#
|
||||
# DESCRIPTION: Verilator Example: XML tests
|
||||
#
|
||||
# Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
# 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
|
||||
#
|
||||
######################################################################
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
module sub
|
||||
#(parameter type TYPE_t = logic)
|
||||
(
|
||||
input TYPE_t in,
|
||||
input TYPE_t in,
|
||||
output TYPE_t out
|
||||
);
|
||||
|
||||
|
||||
@@ -7,16 +7,16 @@
|
||||
|
||||
module top
|
||||
(
|
||||
input clk,
|
||||
input fastclk,
|
||||
input reset_l,
|
||||
input clk,
|
||||
input fastclk,
|
||||
input reset_l,
|
||||
|
||||
output wire [1:0] out_small,
|
||||
output wire [39:0] out_quad,
|
||||
output wire [69:0] out_wide,
|
||||
input [1:0] in_small,
|
||||
input [39:0] in_quad,
|
||||
input [69:0] in_wide
|
||||
input [1:0] in_small,
|
||||
input [39:0] in_quad,
|
||||
input [69:0] in_wide
|
||||
);
|
||||
|
||||
sub #(.TYPE_t(logic [1:0])) sub_small
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
/* config.h.in. Generated from configure.ac by autoheader. */
|
||||
|
||||
/* Define to 1 if you have <alloca.h> and it should be used (not on Ultrix). */
|
||||
#if !defined(__MINGW32__)
|
||||
#if !defined(__MINGW32__) && !defined(__FreeBSD__)
|
||||
# define HAVE_ALLOCA_H 1
|
||||
#endif
|
||||
|
||||
|
||||
@@ -794,6 +794,7 @@ pthread_t thread;
|
||||
pthread_attr_t thread_attr;
|
||||
struct fstWriterContext *xc_parent;
|
||||
#endif
|
||||
unsigned in_pthread : 1;
|
||||
|
||||
size_t fst_orig_break_size;
|
||||
size_t fst_orig_break_add_size;
|
||||
@@ -1806,10 +1807,9 @@ static void *fstWriterFlushContextPrivate1(void *ctx)
|
||||
{
|
||||
struct fstWriterContext *xc = (struct fstWriterContext *)ctx;
|
||||
|
||||
pthread_mutex_lock(&(xc->xc_parent->mutex));
|
||||
fstWriterFlushContextPrivate2(xc);
|
||||
|
||||
pthread_mutex_unlock(&(xc->xc_parent->mutex));
|
||||
|
||||
#ifdef FST_REMOVE_DUPLICATE_VC
|
||||
free(xc->curval_mem);
|
||||
#endif
|
||||
@@ -1818,6 +1818,9 @@ free(xc->vchg_mem);
|
||||
tmpfile_close(&xc->tchn_handle, &xc->tchn_handle_nam);
|
||||
free(xc);
|
||||
|
||||
xc->xc_parent->in_pthread = 0;
|
||||
pthread_mutex_unlock(&(xc->xc_parent->mutex));
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
@@ -1865,7 +1868,15 @@ if(xc->parallel_enabled)
|
||||
xc->section_header_only = 0;
|
||||
xc->secnum++;
|
||||
|
||||
while (xc->in_pthread)
|
||||
{
|
||||
pthread_mutex_lock(&xc->mutex);
|
||||
pthread_mutex_unlock(&xc->mutex);
|
||||
};
|
||||
|
||||
pthread_mutex_lock(&xc->mutex);
|
||||
xc->in_pthread = 1;
|
||||
pthread_mutex_unlock(&xc->mutex);
|
||||
|
||||
pthread_create(&xc->thread, &xc->thread_attr, fstWriterFlushContextPrivate1, xc2);
|
||||
}
|
||||
@@ -1947,6 +1958,12 @@ if(xc && !xc->already_in_close && !xc->already_in_flush)
|
||||
#ifdef FST_WRITER_PARALLEL
|
||||
pthread_mutex_lock(&xc->mutex);
|
||||
pthread_mutex_unlock(&xc->mutex);
|
||||
|
||||
while (xc->in_pthread)
|
||||
{
|
||||
pthread_mutex_lock(&xc->mutex);
|
||||
pthread_mutex_unlock(&xc->mutex);
|
||||
};
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
+934
-630
File diff suppressed because it is too large
Load Diff
+837
-650
File diff suppressed because it is too large
Load Diff
+97
-51
@@ -12,8 +12,9 @@
|
||||
PERL = @PERL@
|
||||
CXX = @CXX@
|
||||
LINK = @CXX@
|
||||
AR = ar
|
||||
AR = ar
|
||||
RANLIB = ranlib
|
||||
OBJCACHE ?= @OBJCACHE@
|
||||
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
@@ -53,6 +54,7 @@ VK_CPPFLAGS_ALWAYS += \
|
||||
-DVM_COVERAGE=$(VM_COVERAGE) \
|
||||
-DVM_SC=$(VM_SC) \
|
||||
-DVM_TRACE=$(VM_TRACE) \
|
||||
-DVM_TRACE_FST=$(VM_TRACE_FST) \
|
||||
$(CFG_CXXFLAGS_NO_UNUSED) \
|
||||
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
@@ -83,27 +85,29 @@ CPPFLAGS += $(VM_USER_CFLAGS)
|
||||
LDFLAGS += $(VM_USER_LDFLAGS)
|
||||
LDLIBS += $(VM_USER_LDLIBS)
|
||||
|
||||
# See the benchmarking section of bin/verilator.
|
||||
# Support class optimizations. This includes the tracing and symbol table.
|
||||
# SystemC takes minutes to optimize, thus it is off by default.
|
||||
#OPT_SLOW =
|
||||
# Fast path optimizations. Most time is spent in these classes.
|
||||
#OPT_FAST = -Os -fstrict-aliasing
|
||||
#OPT_FAST = -O
|
||||
#OPT_FAST =
|
||||
######################################################################
|
||||
# Optimization control.
|
||||
|
||||
#######################################################################
|
||||
##### Aggregates
|
||||
# See also the BENCHMARKING & OPTIMIZATION section of the manual.
|
||||
|
||||
VM_CLASSES += $(VM_CLASSES_FAST) $(VM_CLASSES_SLOW)
|
||||
VM_SUPPORT += $(VM_SUPPORT_FAST) $(VM_SUPPORT_SLOW)
|
||||
# Optimization flags for non performance-critical/rarely executed code.
|
||||
# No optimization by default, which improves compilation speed.
|
||||
OPT_SLOW =
|
||||
# Optimization for performance critical/hot code. Most time is spent in these
|
||||
# routines. Optimizing by default for improved execution speed.
|
||||
OPT_FAST = -Os
|
||||
# Optimization applied to the common run-time library used by verilated models.
|
||||
# For compatibility this is called OPT_GLOBAL even though it only applies to
|
||||
# files in the run-time library. Normally there should be no need for the user
|
||||
# to change this as the library is small, but can have significant speed impact.
|
||||
OPT_GLOBAL = -Os
|
||||
|
||||
#######################################################################
|
||||
##### SystemC builds
|
||||
|
||||
ifeq ($(VM_SC),1)
|
||||
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
|
||||
LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
|
||||
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -I, $(SYSTEMC_INCLUDE))
|
||||
LDFLAGS += $(SYSTEMC_CXX_FLAGS) $(addprefix -L, $(SYSTEMC_LIBDIR))
|
||||
SC_LIBS = -lsystemc
|
||||
ifneq ($(wildcard $(SYSTEMC_LIBDIR)/*numeric_bit*),)
|
||||
# Systemc 1.2.1beta
|
||||
@@ -114,85 +118,127 @@ endif
|
||||
#######################################################################
|
||||
##### Threaded builds
|
||||
|
||||
ifneq ($(VM_C11),0)
|
||||
ifneq ($(VM_C11),)
|
||||
VK_C11=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(VM_THREADS),0)
|
||||
ifneq ($(VM_THREADS),)
|
||||
CPPFLAGS += -DVL_THREADED
|
||||
VK_C11=1
|
||||
VK_LIBS_THREADED=1
|
||||
endif
|
||||
endif
|
||||
|
||||
ifneq ($(VM_TRACE_THREADED),0)
|
||||
ifneq ($(VM_TRACE_THREADED),)
|
||||
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),)
|
||||
# Need C++11 at least, so always default to newest
|
||||
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
|
||||
LDLIBS += $(CFG_LDLIBS_THREADS)
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
##### Stub
|
||||
### Aggregates
|
||||
|
||||
preproc:
|
||||
VM_FAST += $(VM_CLASSES_FAST) $(VM_SUPPORT_FAST)
|
||||
VM_SLOW += $(VM_CLASSES_SLOW) $(VM_SUPPORT_SLOW)
|
||||
|
||||
#######################################################################
|
||||
##### C/H builds
|
||||
### Overall Objects Linking
|
||||
|
||||
LIBS += -lm -lstdc++
|
||||
|
||||
#######################################################################
|
||||
# Overall Objects Linking
|
||||
|
||||
VK_CLASSES_H = $(addsuffix .h, $(VM_CLASSES))
|
||||
VK_CLASSES_CPP = $(addsuffix .cpp, $(VM_CLASSES))
|
||||
|
||||
VK_SUPPORT_CPP = $(addsuffix .cpp, $(VM_SUPPORT))
|
||||
VK_FAST_OBJS = $(addsuffix .o, $(VM_FAST))
|
||||
VK_SLOW_OBJS = $(addsuffix .o, $(VM_SLOW))
|
||||
|
||||
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
|
||||
|
||||
# Note VM_GLOBAL_FAST and VM_GLOBAL_SLOW holds the files required from the
|
||||
# run-time library. In practice everything is actually in VM_GLOBAL_FAST,
|
||||
# but keeping the distinction for compatibility for now.
|
||||
VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
|
||||
|
||||
ifneq ($(VM_PARALLEL_BUILDS),1)
|
||||
# Fast building, all .cpp's in one fell swoop
|
||||
# This saves about 5 sec per module, but can be slower if only a little changes
|
||||
VK_OBJS += $(VM_PREFIX)__ALLcls.o $(VM_PREFIX)__ALLsup.o
|
||||
all_cpp: $(VM_PREFIX)__ALLcls.cpp $(VM_PREFIX)__ALLsup.cpp
|
||||
$(VM_PREFIX)__ALLcls.cpp: $(VK_CLASSES_CPP)
|
||||
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
|
||||
$(VM_PREFIX)__ALLsup.cpp: $(VK_SUPPORT_CPP)
|
||||
# Fast build for small designs: All .cpp files in one fell swoop. This
|
||||
# saves total compute, but can be slower if only a little changes. It is
|
||||
# also a lot slower for medium to large designs when the speed of the C
|
||||
# compiler dominates, which in this mode is not parallelizable.
|
||||
|
||||
VK_OBJS += $(VM_PREFIX)__ALL.o
|
||||
$(VM_PREFIX)__ALL.cpp: $(addsuffix .cpp, $(VM_FAST) $(VM_SLOW))
|
||||
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
|
||||
all_cpp: $(VM_PREFIX)__ALL.cpp
|
||||
else
|
||||
#Slow way of building... Each .cpp file by itself
|
||||
VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT))
|
||||
# Parallel build: Each .cpp file by itself. This can be somewhat slower for
|
||||
# very small designs and examples, but is a lot faster for large designs.
|
||||
|
||||
VK_OBJS += $(VK_FAST_OBJS) $(VK_SLOW_OBJS)
|
||||
endif
|
||||
|
||||
$(VM_PREFIX)__ALL.a: $(VK_OBJS)
|
||||
$(AR) -cr $@ $^
|
||||
$(RANLIB) $@
|
||||
# When archiving just objects (.o), single $(AR) run is enough.
|
||||
# When merging objects (.o) and archives (.a), the following steps are taken.
|
||||
# 1. Extract object files from .a
|
||||
# 2. Create a new archive from extracted .o and given .o
|
||||
%.a:
|
||||
@echo "Archive $(AR) -cr $@ $^"
|
||||
@if test $(words $(filter %.a,$^)) -eq 0; then \
|
||||
$(AR) -cr $@ $^; \
|
||||
$(RANLIB) $@; \
|
||||
else \
|
||||
$(RM) -rf $*__tmpdir; \
|
||||
for archive in $(filter %.a,$^); do \
|
||||
mkdir -p $*__tmpdir/$$(basename $${archive}); \
|
||||
cd $*__tmpdir/$$(basename $${archive}); \
|
||||
$(AR) -x ../../$${archive}; \
|
||||
cd ../..; \
|
||||
done; \
|
||||
$(AR) -cr $@ $(filter %.o,$^) $*__tmpdir/*/*.o; \
|
||||
$(RM) -rf $*__tmpdir; \
|
||||
fi
|
||||
|
||||
$(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS)
|
||||
|
||||
|
||||
######################################################################
|
||||
### Compile rules
|
||||
|
||||
ifneq ($(VM_DEFAULT_RULES),0)
|
||||
$(VM_PREFIX)__ALLcls.o: $(VM_PREFIX)__ALLcls.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
||||
|
||||
$(VM_PREFIX)__ALLsup.o: $(VM_PREFIX)__ALLsup.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
|
||||
|
||||
# VM_GLOBAL_FAST files including verilated.o use this rule
|
||||
# Anything not in $(VK_SLOW_OBJS) or $(VK_GLOBAL_OBJS), including verilated.o
|
||||
# and user files passed on the Verilator command line use this rule.
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
||||
|
||||
%__Slow.o: %__Slow.cpp
|
||||
$(VK_SLOW_OBJS): %.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
|
||||
|
||||
$(VK_GLOBAL_OBJS): %.o: %.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<
|
||||
endif
|
||||
|
||||
#Default rule embedded in make:
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
///**** Product and Version name
|
||||
|
||||
// Autoconf substitutes this with the strings from AC_INIT.
|
||||
#define VERILATOR_PRODUCT "@PACKAGE_NAME@"
|
||||
#define VERILATOR_VERSION "@PACKAGE_VERSION@"
|
||||
#define VERILATOR_PRODUCT "@PACKAGE_NAME@"
|
||||
#define VERILATOR_VERSION "@PACKAGE_VERSION@"
|
||||
|
||||
+141
-137
@@ -47,7 +47,7 @@ public: // But only local to this file
|
||||
// CONSTRUCTORS
|
||||
// Derived classes should call zero() in their constructor
|
||||
VerilatedCovImpItem() {
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
m_keys[i] = KEY_UNDEF;
|
||||
m_vals[i] = 0;
|
||||
}
|
||||
@@ -66,16 +66,19 @@ public: // But only local to this file
|
||||
template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
|
||||
private:
|
||||
// MEMBERS
|
||||
T* m_countp; ///< Count value
|
||||
T* m_countp; ///< Count value
|
||||
public:
|
||||
// METHODS
|
||||
// cppcheck-suppress truncLongCastReturn
|
||||
virtual vluint64_t count() const VL_OVERRIDE { return *m_countp; }
|
||||
virtual void zero() const VL_OVERRIDE { *m_countp = 0; }
|
||||
virtual vluint64_t count() const override { return *m_countp; }
|
||||
virtual void zero() const override { *m_countp = 0; }
|
||||
// CONSTRUCTORS
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
explicit VerilatedCoverItemSpec(T* countp) : m_countp(countp) { *m_countp = 0; }
|
||||
virtual ~VerilatedCoverItemSpec() VL_OVERRIDE {}
|
||||
explicit VerilatedCoverItemSpec(T* countp)
|
||||
: m_countp{countp} {
|
||||
*m_countp = 0;
|
||||
}
|
||||
virtual ~VerilatedCoverItemSpec() override {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -87,28 +90,24 @@ public:
|
||||
class VerilatedCovImp : VerilatedCovImpBase {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::map<std::string,int> ValueIndexMap;
|
||||
typedef std::map<int,std::string> IndexValueMap;
|
||||
typedef std::map<std::string, int> ValueIndexMap;
|
||||
typedef std::map<int, std::string> IndexValueMap;
|
||||
typedef std::deque<VerilatedCovImpItem*> ItemList;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
VerilatedMutex m_mutex; ///< Protects all members, when VL_THREADED. Wrapper deals with setting it.
|
||||
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
||||
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< For each key/value a unique arbitrary index value
|
||||
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
||||
VerilatedMutex m_mutex; ///< Protects all members
|
||||
ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for values
|
||||
IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); ///< Unique arbitrary value for keys
|
||||
ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items
|
||||
|
||||
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex); ///< Item about to insert
|
||||
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex); ///< Filename about to insert
|
||||
int m_insertLineno VL_GUARDED_BY(m_mutex); ///< Line number about to insert
|
||||
VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex) = nullptr; ///< Item about to insert
|
||||
const char* m_insertFilenamep VL_GUARDED_BY(m_mutex) = nullptr; ///< Filename about to insert
|
||||
int m_insertLineno VL_GUARDED_BY(m_mutex) = 0; ///< Line number about to insert
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedCovImp() {
|
||||
m_insertp = NULL;
|
||||
m_insertFilenamep = NULL;
|
||||
m_insertLineno = 0;
|
||||
}
|
||||
VerilatedCovImp() {}
|
||||
VL_UNCOPYABLE(VerilatedCovImp);
|
||||
|
||||
public:
|
||||
~VerilatedCovImp() { clearGuts(); }
|
||||
static VerilatedCovImp& imp() VL_MT_SAFE {
|
||||
@@ -119,10 +118,11 @@ public:
|
||||
private:
|
||||
// PRIVATE METHODS
|
||||
int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) {
|
||||
static int nextIndex = KEY_UNDEF+1;
|
||||
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
||||
static int nextIndex = KEY_UNDEF + 1;
|
||||
const auto iter = m_valueIndexes.find(value);
|
||||
if (iter != m_valueIndexes.end()) return iter->second;
|
||||
nextIndex++; assert(nextIndex>0);
|
||||
nextIndex++;
|
||||
assert(nextIndex > 0); // Didn't rollover
|
||||
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
||||
m_indexValues.insert(std::make_pair(nextIndex, value));
|
||||
return nextIndex;
|
||||
@@ -131,8 +131,9 @@ private:
|
||||
// Quote any special characters
|
||||
std::string rtn;
|
||||
for (const char* pos = text.c_str(); *pos; ++pos) {
|
||||
if (!isprint(*pos) || *pos=='%' || *pos=='"') {
|
||||
char hex[10]; sprintf(hex, "%%%02X", pos[0]);
|
||||
if (!isprint(*pos) || *pos == '%' || *pos == '"') {
|
||||
char hex[10];
|
||||
sprintf(hex, "%%%02X", pos[0]);
|
||||
rtn += hex;
|
||||
} else {
|
||||
rtn += *pos;
|
||||
@@ -145,18 +146,19 @@ private:
|
||||
// don't want applications to either get confused if they use
|
||||
// a letter differently, nor want them to rely on our compression...
|
||||
// (Considered using numeric keys, but will remain back compatible.)
|
||||
if (key.length()<2) return false;
|
||||
if (key.length()==2 && isdigit(key[1])) return false;
|
||||
if (key.length() < 2) return false;
|
||||
if (key.length() == 2 && isdigit(key[1])) return false;
|
||||
return true;
|
||||
}
|
||||
static std::string keyValueFormatter(const std::string& key, const std::string& value) VL_PURE {
|
||||
static std::string keyValueFormatter(const std::string& key,
|
||||
const std::string& value) VL_PURE {
|
||||
std::string name;
|
||||
if (key.length()==1 && isalpha(key[0])) {
|
||||
name += std::string("\001")+key;
|
||||
if (key.length() == 1 && isalpha(key[0])) {
|
||||
name += std::string("\001") + key;
|
||||
} else {
|
||||
name += std::string("\001")+dequote(key);
|
||||
name += std::string("\001") + dequote(key);
|
||||
}
|
||||
name += std::string("\002")+dequote(value);
|
||||
name += std::string("\002") + dequote(value);
|
||||
return name;
|
||||
}
|
||||
static std::string combineHier(const std::string& old, const std::string& add) VL_PURE {
|
||||
@@ -173,28 +175,35 @@ private:
|
||||
// Scan forward to first mismatch
|
||||
const char* apre = a;
|
||||
const char* bpre = b;
|
||||
while (*apre == *bpre) { apre++; bpre++; }
|
||||
while (*apre == *bpre) {
|
||||
apre++;
|
||||
bpre++;
|
||||
}
|
||||
|
||||
// We used to backup and split on only .'s but it seems better to be verbose
|
||||
// and not assume . is the separator
|
||||
std::string prefix = std::string(a, apre-a);
|
||||
std::string prefix = std::string(a, apre - a);
|
||||
|
||||
// Scan backward to last mismatch
|
||||
const char* apost = a+strlen(a)-1;
|
||||
const char* bpost = b+strlen(b)-1;
|
||||
while (*apost == *bpost
|
||||
&& apost>apre && bpost>bpre) { apost--; bpost--; }
|
||||
const char* apost = a + strlen(a) - 1;
|
||||
const char* bpost = b + strlen(b) - 1;
|
||||
while (*apost == *bpost && apost > apre && bpost > bpre) {
|
||||
apost--;
|
||||
bpost--;
|
||||
}
|
||||
|
||||
// Forward to . so we have a whole word
|
||||
std::string suffix = *bpost ? std::string(bpost+1) : "";
|
||||
std::string suffix = *bpost ? std::string(bpost + 1) : "";
|
||||
|
||||
std::string out = prefix+"*"+suffix;
|
||||
std::string out = prefix + "*" + suffix;
|
||||
|
||||
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
|
||||
// cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add
|
||||
// <<"\ncho="<<out<<endl;
|
||||
return out;
|
||||
}
|
||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) VL_REQUIRES(m_mutex) {
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match)
|
||||
VL_REQUIRES(m_mutex) {
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||
// We don't compare keys, only values
|
||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
@@ -207,20 +216,22 @@ private:
|
||||
}
|
||||
static void selftest() VL_MT_SAFE {
|
||||
// Little selftest
|
||||
if (combineHier("a.b.c","a.b.c") !="a.b.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("a.b.c","a.b") !="a.b*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("a.x.c","a.y.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("a.z.z.z.c","a.b.c") !="a.*.c") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("z","a") !="*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("q.a","q.b") !="q.*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("q.za","q.zb") !="q.z*") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier("1.2.3.a","9.8.7.a") !="*.a") VL_FATAL_MT(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
#define SELF_CHECK(got, exp) \
|
||||
do { \
|
||||
if ((got) != (exp)) VL_FATAL_MT(__FILE__, __LINE__, "", "%Error: selftest\n"); \
|
||||
} while (0)
|
||||
SELF_CHECK(combineHier("a.b.c", "a.b.c"), "a.b.c");
|
||||
SELF_CHECK(combineHier("a.b.c", "a.b"), "a.b*");
|
||||
SELF_CHECK(combineHier("a.x.c", "a.y.c"), "a.*.c");
|
||||
SELF_CHECK(combineHier("a.z.z.z.c", "a.b.c"), "a.*.c");
|
||||
SELF_CHECK(combineHier("z", "a"), "*");
|
||||
SELF_CHECK(combineHier("q.a", "q.b"), "q.*");
|
||||
SELF_CHECK(combineHier("q.za", "q.zb"), "q.z*");
|
||||
SELF_CHECK(combineHier("1.2.3.a", "9.8.7.a"), "*.a");
|
||||
#undef SELF_CHECK
|
||||
}
|
||||
void clearGuts() VL_REQUIRES(m_mutex) {
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
VL_DO_DANGLING(delete itemp, itemp);
|
||||
}
|
||||
for (const auto& itemp : m_items) VL_DO_DANGLING(delete itemp, itemp);
|
||||
m_items.clear();
|
||||
m_indexValues.clear();
|
||||
m_valueIndexes.clear();
|
||||
@@ -230,16 +241,15 @@ public:
|
||||
// PUBLIC METHODS
|
||||
void clear() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
clearGuts();
|
||||
}
|
||||
void clearNonMatch(const char* matchp) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
if (matchp && matchp[0]) {
|
||||
ItemList newlist;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
for (const auto& itemp : m_items) {
|
||||
if (!itemMatchesString(itemp, matchp)) {
|
||||
VL_DO_DANGLING(delete itemp, itemp);
|
||||
} else {
|
||||
@@ -251,50 +261,48 @@ public:
|
||||
}
|
||||
void zero() VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
for (ItemList::const_iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
(*it)->zero();
|
||||
}
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
for (const auto& itemp : m_items) itemp->zero();
|
||||
}
|
||||
|
||||
// We assume there's always call to i/f/p in that order
|
||||
void inserti(VerilatedCovImpItem* itemp) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
assert(!m_insertp);
|
||||
m_insertp = itemp;
|
||||
}
|
||||
void insertf(const char* filenamep, int lineno) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
m_insertFilenamep = filenamep;
|
||||
m_insertLineno = lineno;
|
||||
}
|
||||
void insertp(const char* ckeyps[MAX_KEYS],
|
||||
const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
void insertp(const char* ckeyps[MAX_KEYS], const char* valps[MAX_KEYS]) VL_EXCLUDES(m_mutex) {
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
assert(m_insertp);
|
||||
// First two key/vals are filename
|
||||
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
||||
ckeyps[0] = "filename";
|
||||
valps[0] = m_insertFilenamep;
|
||||
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
||||
ckeyps[1]="lineno"; valps[1]=linestr.c_str();
|
||||
ckeyps[1] = "lineno";
|
||||
valps[1] = linestr.c_str();
|
||||
// Default page if not specified
|
||||
const char* fnstartp = m_insertFilenamep;
|
||||
while (const char* foundp = strchr(fnstartp,'/')) fnstartp = foundp+1;
|
||||
while (const char* foundp = strchr(fnstartp, '/')) fnstartp = foundp + 1;
|
||||
const char* fnendp = fnstartp;
|
||||
while (*fnendp && *fnendp!='.') fnendp++;
|
||||
std::string page_default = "sp_user/"+std::string(fnstartp, fnendp-fnstartp);
|
||||
ckeyps[2]="page"; valps[2]=page_default.c_str();
|
||||
for (; *fnendp && *fnendp != '.'; fnendp++) {}
|
||||
std::string page_default = "sp_user/" + std::string(fnstartp, fnendp - fnstartp);
|
||||
ckeyps[2] = "page";
|
||||
valps[2] = page_default.c_str();
|
||||
|
||||
// Keys -> strings
|
||||
std::string keys[MAX_KEYS];
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (ckeyps[i] && ckeyps[i][0]) {
|
||||
keys[i] = ckeyps[i];
|
||||
}
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
if (ckeyps[i] && ckeyps[i][0]) { keys[i] = ckeyps[i]; }
|
||||
}
|
||||
// Ignore empty keys
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
if (!keys[i].empty()) {
|
||||
for (int j=i+1; j<MAX_KEYS; ++j) {
|
||||
for (int j = i + 1; j < MAX_KEYS; ++j) {
|
||||
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
|
||||
keys[i] = "";
|
||||
break;
|
||||
@@ -304,30 +312,30 @@ public:
|
||||
}
|
||||
// Insert the values
|
||||
int addKeynum = 0;
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
const std::string key = keys[i];
|
||||
if (!keys[i].empty()) {
|
||||
const std::string val = valps[i];
|
||||
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
||||
// cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
||||
m_insertp->m_keys[addKeynum] = valueIndex(key);
|
||||
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
||||
addKeynum++;
|
||||
if (!legalKey(key)) {
|
||||
if (VL_UNCOVERABLE(!legalKey(key))) {
|
||||
std::string msg
|
||||
= ("%Error: Coverage keys of one character, or letter+digit are illegal: "
|
||||
+key);
|
||||
+ key); // LCOV_EXCL_LINE
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
m_items.push_back(m_insertp);
|
||||
// Prepare for next
|
||||
m_insertp = NULL;
|
||||
m_insertp = nullptr;
|
||||
}
|
||||
|
||||
void write(const char* filename) VL_EXCLUDES(m_mutex) {
|
||||
Verilated::quiesce();
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
#ifndef VM_COVERAGE
|
||||
VL_FATAL_MT("", 0, "", "%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||
#endif
|
||||
@@ -335,22 +343,21 @@ public:
|
||||
|
||||
std::ofstream os(filename);
|
||||
if (os.fail()) {
|
||||
std::string msg = std::string("%Error: Can't write '")+filename+"'";
|
||||
std::string msg = std::string("%Error: Can't write '") + filename + "'";
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
return;
|
||||
}
|
||||
os << "# SystemC::Coverage-3\n";
|
||||
|
||||
// Build list of events; totalize if collapsing hierarchy
|
||||
typedef std::map<std::string,std::pair<std::string,vluint64_t> > EventMap;
|
||||
typedef std::map<std::string, std::pair<std::string, vluint64_t>> EventMap;
|
||||
EventMap eventCounts;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
for (const auto& itemp : m_items) {
|
||||
std::string name;
|
||||
std::string hier;
|
||||
bool per_instance = false;
|
||||
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
for (int i = 0; i < MAX_KEYS; ++i) {
|
||||
if (itemp->m_keys[i] != KEY_UNDEF) {
|
||||
std::string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
|
||||
std::string val = m_indexValues[itemp->m_vals[i]];
|
||||
@@ -376,23 +383,23 @@ public:
|
||||
// inefficient)
|
||||
|
||||
// Find or insert the named event
|
||||
EventMap::iterator cit = eventCounts.find(name);
|
||||
const auto cit = eventCounts.find(name);
|
||||
if (cit != eventCounts.end()) {
|
||||
const std::string& oldhier = cit->second.first;
|
||||
cit->second.second += itemp->count();
|
||||
cit->second.first = combineHier(oldhier, hier);
|
||||
cit->second.first = combineHier(oldhier, hier);
|
||||
} else {
|
||||
eventCounts.insert(std::make_pair(name, make_pair(hier, itemp->count())));
|
||||
}
|
||||
}
|
||||
|
||||
// Output body
|
||||
for (EventMap::const_iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
||||
os<<"C '"<<std::dec;
|
||||
os<<it->first;
|
||||
if (!it->second.first.empty()) os<<keyValueFormatter(VL_CIK_HIER, it->second.first);
|
||||
os<<"' "<<it->second.second;
|
||||
os<<std::endl;
|
||||
for (const auto& i : eventCounts) {
|
||||
os << "C '" << std::dec;
|
||||
os << i.first;
|
||||
if (!i.second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, i.second.first);
|
||||
os << "' " << i.second.second;
|
||||
os << std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -400,15 +407,11 @@ public:
|
||||
//=============================================================================
|
||||
// VerilatedCov
|
||||
|
||||
void VerilatedCov::clear() VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().clear();
|
||||
}
|
||||
void VerilatedCov::clear() VL_MT_SAFE { VerilatedCovImp::imp().clear(); }
|
||||
void VerilatedCov::clearNonMatch(const char* matchp) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().clearNonMatch(matchp);
|
||||
}
|
||||
void VerilatedCov::zero() VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().zero();
|
||||
}
|
||||
void VerilatedCov::zero() VL_MT_SAFE { VerilatedCovImp::imp().zero(); }
|
||||
void VerilatedCov::write(const char* filenamep) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().write(filenamep);
|
||||
}
|
||||
@@ -422,48 +425,49 @@ void VerilatedCov::_insertf(const char* filename, int lineno) VL_MT_SAFE {
|
||||
VerilatedCovImp::imp().insertf(filename, lineno);
|
||||
}
|
||||
|
||||
#define K(n) const char* key ## n
|
||||
#define A(n) const char* key ## n, const char* valp ## n // Argument list
|
||||
#define C(n) key ## n, valp ## n // Calling argument list
|
||||
#define N(n) "","" // Null argument list
|
||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19),
|
||||
A(20),A(21),A(22),A(23),A(24),A(25),A(26),A(27),A(28),A(29)) VL_MT_SAFE {
|
||||
#define K(n) const char* key##n
|
||||
#define A(n) const char *key##n, const char *valp##n // Argument list
|
||||
#define C(n) key##n, valp##n // Calling argument list
|
||||
#define N(n) "", "" // Null argument list
|
||||
void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10),
|
||||
A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20),
|
||||
A(21), A(22), A(23), A(24), A(25), A(26), A(27), A(28),
|
||||
A(29)) VL_MT_SAFE {
|
||||
const char* keyps[VerilatedCovImpBase::MAX_KEYS]
|
||||
= {NULL,NULL,NULL, // filename,lineno,page
|
||||
key0,key1,key2,key3,key4,key5,key6,key7,key8,key9,
|
||||
key10,key11,key12,key13,key14,key15,key16,key17,key18,key19,
|
||||
key20,key21,key22,key23,key24,key25,key26,key27,key28,key29};
|
||||
= {nullptr, nullptr, nullptr, // filename,lineno,page
|
||||
key0, key1, key2, key3, key4, key5, key6, key7, key8, key9,
|
||||
key10, key11, key12, key13, key14, key15, key16, key17, key18, key19,
|
||||
key20, key21, key22, key23, key24, key25, key26, key27, key28, key29};
|
||||
const char* valps[VerilatedCovImpBase::MAX_KEYS]
|
||||
= {NULL,NULL,NULL, // filename,lineno,page
|
||||
valp0,valp1,valp2,valp3,valp4,valp5,valp6,valp7,valp8,valp9,
|
||||
valp10,valp11,valp12,valp13,valp14,valp15,valp16,valp17,valp18,valp19,
|
||||
valp20,valp21,valp22,valp23,valp24,valp25,valp26,valp27,valp28,valp29};
|
||||
= {nullptr, nullptr, nullptr, // filename,lineno,page
|
||||
valp0, valp1, valp2, valp3, valp4, valp5, valp6, valp7, valp8, valp9,
|
||||
valp10, valp11, valp12, valp13, valp14, valp15, valp16, valp17, valp18, valp19,
|
||||
valp20, valp21, valp22, valp23, valp24, valp25, valp26, valp27, valp28, valp29};
|
||||
VerilatedCovImp::imp().insertp(keyps, valps);
|
||||
}
|
||||
|
||||
// And versions with fewer arguments (oh for a language with named parameters!)
|
||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) VL_MT_SAFE {
|
||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8),
|
||||
A(9)) VL_MT_SAFE {
|
||||
_insertp(C(0), C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), N(10), N(11), N(12),
|
||||
N(13), N(14), N(15), N(16), N(17), N(18), N(19), N(20), N(21), N(22), N(23), N(24),
|
||||
N(25), N(26), N(27), N(28), N(29));
|
||||
}
|
||||
void VerilatedCov::_insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
|
||||
A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) VL_MT_SAFE {
|
||||
_insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
|
||||
C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
void VerilatedCov::_insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10),
|
||||
A(11), A(12), A(13), A(14), A(15), A(16), A(17), A(18),
|
||||
A(19)) VL_MT_SAFE {
|
||||
_insertp(C(0), C(1), C(2), C(3), C(4), C(5), C(6), C(7), C(8), C(9), C(10), C(11), C(12),
|
||||
C(13), C(14), C(15), C(16), C(17), C(18), C(19), N(20), N(21), N(22), N(23), N(24),
|
||||
N(25), N(26), N(27), N(28), N(29));
|
||||
}
|
||||
// Backward compatibility for Verilator
|
||||
void VerilatedCov::_insertp(A(0), A(1), K(2),int val2, K(3),int val3,
|
||||
K(4),const std::string& val4, A(5),A(6)) VL_MT_SAFE {
|
||||
void VerilatedCov::_insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4),
|
||||
const std::string& val4, A(5), A(6), A(7)) VL_MT_SAFE {
|
||||
std::string val2str = vlCovCvtToStr(val2);
|
||||
std::string val3str = vlCovCvtToStr(val3);
|
||||
_insertp(C(0),C(1),
|
||||
key2,val2str.c_str(), key3,val3str.c_str(), key4, val4.c_str(),
|
||||
C(5),C(6),N(7),N(8),N(9),
|
||||
N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
|
||||
N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
|
||||
_insertp(C(0), C(1), key2, val2str.c_str(), key3, val3str.c_str(), key4, val4.c_str(), C(5),
|
||||
C(6), C(7), N(8), N(9), N(10), N(11), N(12), N(13), N(14), N(15), N(16), N(17), N(18),
|
||||
N(19), N(20), N(21), N(22), N(23), N(24), N(25), N(26), N(27), N(28), N(29));
|
||||
}
|
||||
#undef A
|
||||
#undef C
|
||||
|
||||
+21
-19
@@ -28,17 +28,17 @@
|
||||
//=============================================================================
|
||||
/// Conditionally compile coverage code
|
||||
|
||||
// clang-format off
|
||||
#ifdef VM_COVERAGE
|
||||
# define VL_IF_COVER(stmts) \
|
||||
do { \
|
||||
stmts; \
|
||||
} while (false)
|
||||
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.
|
||||
@@ -68,16 +68,17 @@
|
||||
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
|
||||
/// }
|
||||
|
||||
#define VL_COVER_INSERT(countp,...) \
|
||||
VL_IF_COVER(VerilatedCov::_inserti(countp); \
|
||||
VerilatedCov::_insertf(__FILE__, __LINE__); \
|
||||
#define VL_COVER_INSERT(countp, ...) \
|
||||
VL_IF_COVER(VerilatedCov::_inserti(countp); VerilatedCov::_insertf(__FILE__, __LINE__); \
|
||||
VerilatedCov::_insertp("hier", name(), __VA_ARGS__))
|
||||
|
||||
//=============================================================================
|
||||
/// Convert VL_COVER_INSERT value arguments to strings
|
||||
|
||||
template< class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
|
||||
std::ostringstream os; os<<t; return os.str();
|
||||
template <class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
|
||||
std::ostringstream os;
|
||||
os << t;
|
||||
return os.str();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
@@ -89,6 +90,7 @@ template< class T> std::string vlCovCvtToStr(const T& t) VL_PURE {
|
||||
|
||||
class VerilatedCov {
|
||||
VL_UNCOPYABLE(VerilatedCov);
|
||||
|
||||
public:
|
||||
// GLOBAL METHODS
|
||||
/// Return default filename
|
||||
@@ -108,18 +110,18 @@ public:
|
||||
// We could have just the maximum argument version, but this compiles
|
||||
// much slower (nearly 2x) than having smaller versions also. However
|
||||
// there's not much more gain in having a version for each number of args.
|
||||
#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 = NULL, const char* valp ## n = NULL // Argument list
|
||||
static void _insertp(D(0),D(1),D(2),D(3),D(4),D(5),D(6),D(7),D(8),D(9));
|
||||
static void _insertp(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));
|
||||
static void _insertp(A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)
|
||||
,A(10),A(11),A(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));
|
||||
#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
|
||||
static void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9));
|
||||
static void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), D(11),
|
||||
D(12), D(13), D(14), D(15), D(16), D(17), D(18), D(19));
|
||||
static void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), 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));
|
||||
// Backward compatibility for Verilator
|
||||
static void _insertp(A(0), A(1), K(2),int val2, K(3),int val3,
|
||||
K(4),const std::string& val4, A(5),A(6));
|
||||
static void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4,
|
||||
A(5), A(6), A(7));
|
||||
|
||||
#undef K
|
||||
#undef A
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#define VLCOVGEN_ITEM(string_parsed_by_vlcovgen)
|
||||
|
||||
// clang-format off
|
||||
VLCOVGEN_ITEM("name=>'col0_name', short=>'C0', group=>1, default=>undef, descr=>'The column title for the header line of this column'")
|
||||
VLCOVGEN_ITEM("name=>'col1_name', short=>'C1', group=>1, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'col2_name', short=>'C2', group=>1, default=>undef, ")
|
||||
@@ -37,6 +38,7 @@ VLCOVGEN_ITEM("name=>'filename', short=>'f', group=>1, default=>undef, descr
|
||||
VLCOVGEN_ITEM("name=>'groupdesc', short=>'d', group=>1, default=>'', descr=>'Description of the covergroup this item belongs to'")
|
||||
VLCOVGEN_ITEM("name=>'groupname', short=>'g', group=>1, default=>'', descr=>'Group name of the covergroup this item belongs to'")
|
||||
VLCOVGEN_ITEM("name=>'groupcmt', short=>'O', group=>1, default=>'', ")
|
||||
VLCOVGEN_ITEM("name=>'linescov', short=>'S', group=>1, default=>'', descr=>'List of comma-separated lines covered'")
|
||||
VLCOVGEN_ITEM("name=>'per_instance',short=>'P', group=>1, default=>0, descr=>'True if every hierarchy is independently counted; otherwise all hierarchies will be combined into a single count'")
|
||||
VLCOVGEN_ITEM("name=>'row0_name', short=>'R0', group=>1, default=>undef, descr=>'The row title for the header line of this row'")
|
||||
VLCOVGEN_ITEM("name=>'row1_name', short=>'R1', group=>1, default=>undef, ")
|
||||
@@ -59,6 +61,7 @@ VLCOVGEN_ITEM("name=>'row1', short=>'r1', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'row2', short=>'r2', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'row3', short=>'r3', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr=>'For totaling items, weight of this item'")
|
||||
// clang-format on
|
||||
|
||||
// VLCOVGEN_CIK_AUTO_EDIT_BEGIN
|
||||
#define VL_CIK_COL0 "c0"
|
||||
@@ -78,6 +81,7 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr
|
||||
#define VL_CIK_HIER "h"
|
||||
#define VL_CIK_LIMIT "L"
|
||||
#define VL_CIK_LINENO "l"
|
||||
#define VL_CIK_LINESCOV "S"
|
||||
#define VL_CIK_PER_INSTANCE "P"
|
||||
#define VL_CIK_ROW0 "r0"
|
||||
#define VL_CIK_ROW0_NAME "R0"
|
||||
@@ -119,6 +123,7 @@ public:
|
||||
if (key == "hier") return VL_CIK_HIER;
|
||||
if (key == "limit") return VL_CIK_LIMIT;
|
||||
if (key == "lineno") return VL_CIK_LINENO;
|
||||
if (key == "linescov") return VL_CIK_LINESCOV;
|
||||
if (key == "per_instance") return VL_CIK_PER_INSTANCE;
|
||||
if (key == "row0") return VL_CIK_ROW0;
|
||||
if (key == "row0_name") return VL_CIK_ROW0_NAME;
|
||||
|
||||
+313
-237
@@ -40,88 +40,80 @@
|
||||
// Not supported yet
|
||||
#define _VL_SVDPI_UNIMP() \
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", \
|
||||
(std::string("%%Error: Unsupported DPI function: ")+VL_FUNC).c_str())
|
||||
(std::string("%%Error: Unsupported DPI function: ") + VL_FUNC).c_str())
|
||||
|
||||
#define _VL_SVDPI_WARN(...) \
|
||||
VL_PRINTF_MT(__VA_ARGS__)
|
||||
#define _VL_SVDPI_WARN(...) VL_PRINTF_MT(__VA_ARGS__)
|
||||
|
||||
// Function requires a "context" in the import declaration
|
||||
#define _VL_SVDPI_CONTEXT_WARN() \
|
||||
_VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n");
|
||||
_VL_SVDPI_WARN("%%Warning: DPI C Function called by Verilog DPI import with missing " \
|
||||
"'context' keyword.\n")
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
// DPI ROUTINES
|
||||
|
||||
const char* svDpiVersion() {
|
||||
return "1800-2005";
|
||||
}
|
||||
const char* svDpiVersion() { return "1800-2005"; }
|
||||
|
||||
//======================================================================
|
||||
// Bit-select utility functions.
|
||||
|
||||
svBit svGetBitselBit(const svBitVecVal* sp, int bit) {
|
||||
return VL_BITRSHIFT_W(sp,bit) & 1;
|
||||
}
|
||||
svBit svGetBitselBit(const svBitVecVal* sp, int bit) { return VL_BITRSHIFT_W(sp, bit) & 1; }
|
||||
svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
|
||||
// Not VL_BITRSHIFT_W as sp is a different structure type
|
||||
// Verilator doesn't support X/Z so only aval
|
||||
return (((sp[VL_BITWORD_I(bit)].aval >> VL_BITBIT_I(bit)) & 1)
|
||||
| (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1)<<1));
|
||||
| (((sp[VL_BITWORD_I(bit)].bval >> VL_BITBIT_I(bit)) & 1) << 1));
|
||||
}
|
||||
|
||||
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) {
|
||||
VL_ASSIGNBIT_WI(32, bit, dp, s);
|
||||
}
|
||||
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) { VL_ASSIGNBIT_WI(32, bit, dp, s); }
|
||||
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
|
||||
// Verilator doesn't support X/Z so only aval
|
||||
dp[VL_BITWORD_I(bit)].aval
|
||||
= ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1)<<VL_BITBIT_I(bit)))
|
||||
| ((s&1)<<VL_BITBIT_I(bit)));
|
||||
dp[VL_BITWORD_I(bit)].bval
|
||||
= ((dp[VL_BITWORD_I(bit)].bval & ~(VL_UL(1)<<VL_BITBIT_I(bit)))
|
||||
| ((s&2)>>1<<VL_BITBIT_I(bit)));
|
||||
dp[VL_BITWORD_I(bit)].aval = ((dp[VL_BITWORD_I(bit)].aval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
|
||||
| ((s & 1) << VL_BITBIT_I(bit)));
|
||||
dp[VL_BITWORD_I(bit)].bval = ((dp[VL_BITWORD_I(bit)].bval & ~(VL_UL(1) << VL_BITBIT_I(bit)))
|
||||
| ((s & 2) >> 1 << VL_BITBIT_I(bit)));
|
||||
}
|
||||
|
||||
void svGetPartselBit(svBitVecVal* dp, const svBitVecVal* sp, int lsb, int width) {
|
||||
// See also VL_SEL_WWI
|
||||
int msb = lsb+width-1;
|
||||
int msb = lsb + width - 1;
|
||||
int word_shift = VL_BITWORD_I(lsb);
|
||||
if (VL_BITBIT_I(lsb)==0) {
|
||||
if (VL_BITBIT_I(lsb) == 0) {
|
||||
// Just a word extract
|
||||
for (int i=0; i<VL_WORDS_I(width); ++i) dp[i] = sp[i+word_shift];
|
||||
for (int i = 0; i < VL_WORDS_I(width); ++i) dp[i] = sp[i + word_shift];
|
||||
} else {
|
||||
int loffset = lsb & VL_SIZEBITS_I;
|
||||
int nbitsfromlow = 32-loffset; // bits that end up in lword (know loffset!=0)
|
||||
int nbitsfromlow = 32 - loffset; // bits that end up in lword (know loffset!=0)
|
||||
// Middle words
|
||||
int words = VL_WORDS_I(msb-lsb+1);
|
||||
for (int i=0; i<words; ++i) {
|
||||
dp[i] = sp[i+word_shift]>>loffset;
|
||||
int upperword = i+word_shift+1;
|
||||
int words = VL_WORDS_I(msb - lsb + 1);
|
||||
for (int i = 0; i < words; ++i) {
|
||||
dp[i] = sp[i + word_shift] >> loffset;
|
||||
int upperword = i + word_shift + 1;
|
||||
if (upperword <= static_cast<int>(VL_BITWORD_I(msb))) {
|
||||
dp[i] |= sp[upperword] << nbitsfromlow;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Clean result
|
||||
dp[VL_WORDS_I(width)-1] &= VL_MASK_I(width);
|
||||
dp[VL_WORDS_I(width) - 1] &= VL_MASK_I(width);
|
||||
}
|
||||
void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int lsb, int width) {
|
||||
int msb = lsb+width-1;
|
||||
int msb = lsb + width - 1;
|
||||
int word_shift = VL_BITWORD_I(lsb);
|
||||
if (VL_BITBIT_I(lsb)==0) {
|
||||
if (VL_BITBIT_I(lsb) == 0) {
|
||||
// Just a word extract
|
||||
for (int i=0; i<VL_WORDS_I(width); ++i) dp[i] = sp[i+word_shift];
|
||||
for (int i = 0; i < VL_WORDS_I(width); ++i) dp[i] = sp[i + word_shift];
|
||||
} else {
|
||||
int loffset = lsb & VL_SIZEBITS_I;
|
||||
int nbitsfromlow = 32-loffset; // bits that end up in lword (know loffset!=0)
|
||||
int nbitsfromlow = 32 - loffset; // bits that end up in lword (know loffset!=0)
|
||||
// Middle words
|
||||
int words = VL_WORDS_I(msb-lsb+1);
|
||||
for (int i=0; i<words; ++i) {
|
||||
dp[i].aval = sp[i+word_shift].aval >> loffset;
|
||||
dp[i].bval = sp[i+word_shift].bval >> loffset;
|
||||
int upperword = i+word_shift+1;
|
||||
int words = VL_WORDS_I(msb - lsb + 1);
|
||||
for (int i = 0; i < words; ++i) {
|
||||
dp[i].aval = sp[i + word_shift].aval >> loffset;
|
||||
dp[i].bval = sp[i + word_shift].bval >> loffset;
|
||||
int upperword = i + word_shift + 1;
|
||||
if (upperword <= static_cast<int>(VL_BITWORD_I(msb))) {
|
||||
dp[i].aval |= sp[upperword].aval << nbitsfromlow;
|
||||
dp[i].bval |= sp[upperword].bval << nbitsfromlow;
|
||||
@@ -129,58 +121,56 @@ void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int lsb, int
|
||||
}
|
||||
}
|
||||
// Clean result
|
||||
dp[VL_WORDS_I(width)-1].aval &= VL_MASK_I(width);
|
||||
dp[VL_WORDS_I(width)-1].bval &= VL_MASK_I(width);
|
||||
dp[VL_WORDS_I(width) - 1].aval &= VL_MASK_I(width);
|
||||
dp[VL_WORDS_I(width) - 1].bval &= VL_MASK_I(width);
|
||||
}
|
||||
void svPutPartselBit(svBitVecVal* dp, const svBitVecVal s, int lbit, int width) {
|
||||
// See also _VL_INSERT_WI
|
||||
int hbit = lbit+width-1;
|
||||
int hbit = lbit + width - 1;
|
||||
int hoffset = VL_BITBIT_I(hbit);
|
||||
int loffset = VL_BITBIT_I(lbit);
|
||||
if (hoffset==VL_SIZEBITS_I && loffset==0) {
|
||||
if (hoffset == VL_SIZEBITS_I && loffset == 0) {
|
||||
// Fast and common case, word based insertion
|
||||
dp[VL_BITWORD_I(lbit)] = s;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
int hword = VL_BITWORD_I(hbit);
|
||||
int lword = VL_BITWORD_I(lbit);
|
||||
if (hword==lword) { // know < 32 bits because above checks it
|
||||
IData insmask = (VL_MASK_I(hoffset-loffset+1))<<loffset;
|
||||
dp[lword] = (dp[lword] & ~insmask) | ((s<<loffset) & insmask);
|
||||
if (hword == lword) { // know < 32 bits because above checks it
|
||||
IData insmask = (VL_MASK_I(hoffset - loffset + 1)) << loffset;
|
||||
dp[lword] = (dp[lword] & ~insmask) | ((s << loffset) & insmask);
|
||||
} else {
|
||||
IData hinsmask = (VL_MASK_I(hoffset-0+1))<<0;
|
||||
IData linsmask = (VL_MASK_I(31-loffset+1))<<loffset;
|
||||
int nbitsonright = 32-loffset; // bits that end up in lword
|
||||
dp[lword] = (dp[lword] & ~linsmask) | ((s<<loffset) & linsmask);
|
||||
dp[hword] = (dp[hword] & ~hinsmask) | ((s>>nbitsonright) & hinsmask);
|
||||
IData hinsmask = (VL_MASK_I(hoffset - 0 + 1)) << 0;
|
||||
IData linsmask = (VL_MASK_I(31 - loffset + 1)) << loffset;
|
||||
int nbitsonright = 32 - loffset; // bits that end up in lword
|
||||
dp[lword] = (dp[lword] & ~linsmask) | ((s << loffset) & linsmask);
|
||||
dp[hword] = (dp[hword] & ~hinsmask) | ((s >> nbitsonright) & hinsmask);
|
||||
}
|
||||
}
|
||||
}
|
||||
// cppcheck-suppress passedByValue
|
||||
void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int width) {
|
||||
int hbit = lbit+width-1;
|
||||
int hbit = lbit + width - 1;
|
||||
int hoffset = VL_BITBIT_I(hbit);
|
||||
int loffset = VL_BITBIT_I(lbit);
|
||||
if (hoffset==VL_SIZEBITS_I && loffset==0) {
|
||||
if (hoffset == VL_SIZEBITS_I && loffset == 0) {
|
||||
// Fast and common case, word based insertion
|
||||
dp[VL_BITWORD_I(lbit)].aval = s.aval;
|
||||
dp[VL_BITWORD_I(lbit)].bval = s.bval;
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
int hword = VL_BITWORD_I(hbit);
|
||||
int lword = VL_BITWORD_I(lbit);
|
||||
if (hword==lword) { // know < 32 bits because above checks it
|
||||
IData insmask = (VL_MASK_I(hoffset-loffset+1))<<loffset;
|
||||
dp[lword].aval = (dp[lword].aval & ~insmask) | ((s.aval<<loffset) & insmask);
|
||||
dp[lword].bval = (dp[lword].bval & ~insmask) | ((s.bval<<loffset) & insmask);
|
||||
if (hword == lword) { // know < 32 bits because above checks it
|
||||
IData insmask = (VL_MASK_I(hoffset - loffset + 1)) << loffset;
|
||||
dp[lword].aval = (dp[lword].aval & ~insmask) | ((s.aval << loffset) & insmask);
|
||||
dp[lword].bval = (dp[lword].bval & ~insmask) | ((s.bval << loffset) & insmask);
|
||||
} else {
|
||||
IData hinsmask = (VL_MASK_I(hoffset-0+1))<<0;
|
||||
IData linsmask = (VL_MASK_I(31-loffset+1))<<loffset;
|
||||
int nbitsonright = 32-loffset; // bits that end up in lword
|
||||
dp[lword].aval = (dp[lword].aval & ~linsmask) | ((s.aval<<loffset) & linsmask);
|
||||
dp[lword].bval = (dp[lword].bval & ~linsmask) | ((s.bval<<loffset) & linsmask);
|
||||
dp[hword].aval = (dp[hword].aval & ~hinsmask) | ((s.aval>>nbitsonright) & hinsmask);
|
||||
dp[hword].bval = (dp[hword].bval & ~hinsmask) | ((s.bval>>nbitsonright) & hinsmask);
|
||||
IData hinsmask = (VL_MASK_I(hoffset - 0 + 1)) << 0;
|
||||
IData linsmask = (VL_MASK_I(31 - loffset + 1)) << loffset;
|
||||
int nbitsonright = 32 - loffset; // bits that end up in lword
|
||||
dp[lword].aval = (dp[lword].aval & ~linsmask) | ((s.aval << loffset) & linsmask);
|
||||
dp[lword].bval = (dp[lword].bval & ~linsmask) | ((s.bval << loffset) & linsmask);
|
||||
dp[hword].aval = (dp[hword].aval & ~hinsmask) | ((s.aval >> nbitsonright) & hinsmask);
|
||||
dp[hword].bval = (dp[hword].bval & ~hinsmask) | ((s.bval >> nbitsonright) & hinsmask);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -191,7 +181,7 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w
|
||||
static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) {
|
||||
if (VL_UNLIKELY(!h)) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"%%Error: DPI svOpenArrayHandle function called with NULL handle");
|
||||
"%%Error: DPI svOpenArrayHandle function called with nullptr handle");
|
||||
}
|
||||
const VerilatedDpiOpenVar* varp = reinterpret_cast<const VerilatedDpiOpenVar*>(h);
|
||||
if (VL_UNLIKELY(!varp->magicOk())) {
|
||||
@@ -204,31 +194,18 @@ static inline const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHa
|
||||
//======================================================================
|
||||
// Open array querying functions
|
||||
|
||||
int svLeft(const svOpenArrayHandle h, int d) {
|
||||
return _vl_openhandle_varp(h)->left(d);
|
||||
}
|
||||
int svRight(const svOpenArrayHandle h, int d) {
|
||||
return _vl_openhandle_varp(h)->right(d);
|
||||
}
|
||||
int svLow(const svOpenArrayHandle h, int d) {
|
||||
return _vl_openhandle_varp(h)->low(d);
|
||||
}
|
||||
int svHigh(const svOpenArrayHandle h, int d) {
|
||||
return _vl_openhandle_varp(h)->high(d);
|
||||
}
|
||||
int svIncrement(const svOpenArrayHandle h, int d) {
|
||||
return _vl_openhandle_varp(h)->increment(d);
|
||||
}
|
||||
int svSize(const svOpenArrayHandle h, int d) {
|
||||
return _vl_openhandle_varp(h)->elements(d);
|
||||
}
|
||||
int svDimensions(const svOpenArrayHandle h) {
|
||||
return _vl_openhandle_varp(h)->udims();
|
||||
}
|
||||
/// Return pointer to open array data, or NULL if not in IEEE standard C layout
|
||||
int svLeft(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->left(d); }
|
||||
int svRight(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->right(d); }
|
||||
int svLow(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->low(d); }
|
||||
int svHigh(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->high(d); }
|
||||
int svIncrement(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->increment(d); }
|
||||
int svSize(const svOpenArrayHandle h, int d) { return _vl_openhandle_varp(h)->elements(d); }
|
||||
int svDimensions(const svOpenArrayHandle h) { return _vl_openhandle_varp(h)->udims(); }
|
||||
|
||||
/// Return pointer to open array data, or nullptr if not in IEEE standard C layout
|
||||
void* svGetArrayPtr(const svOpenArrayHandle h) {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
|
||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
|
||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return nullptr;
|
||||
return varp->datap();
|
||||
}
|
||||
/// Return size of open array, or 0 if not in IEEE standard C layout
|
||||
@@ -242,37 +219,40 @@ 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) {
|
||||
static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, int indx1,
|
||||
int indx2, int indx3) {
|
||||
void* datap = varp->datap();
|
||||
if (VL_UNLIKELY(nargs != varp->udims())) {
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function called on"
|
||||
" %d dimensional array using %d dimensional function.\n",
|
||||
varp->udims(), nargs);
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
if (nargs>=1) {
|
||||
if (nargs >= 1) {
|
||||
datap = varp->datapAdjustIndex(datap, 1, indx1);
|
||||
if (VL_UNLIKELY(!datap)) {
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 out of bounds; %d outside [%d:%d].\n",
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 1 "
|
||||
"out of bounds; %d outside [%d:%d].\n",
|
||||
indx1, varp->left(1), varp->right(1));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (nargs>=2) {
|
||||
if (nargs >= 2) {
|
||||
datap = varp->datapAdjustIndex(datap, 2, indx2);
|
||||
if (VL_UNLIKELY(!datap)) {
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 out of bounds; %d outside [%d:%d].\n",
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 2 "
|
||||
"out of bounds; %d outside [%d:%d].\n",
|
||||
indx2, varp->left(2), varp->right(2));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (nargs>=3) {
|
||||
if (nargs >= 3) {
|
||||
datap = varp->datapAdjustIndex(datap, 3, indx3);
|
||||
if (VL_UNLIKELY(!datap)) {
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 out of bounds; %d outside [%d:%d].\n",
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function index 3 "
|
||||
"out of bounds; %d outside [%d:%d].\n",
|
||||
indx1, varp->left(3), varp->right(3));
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return datap;
|
||||
@@ -280,40 +260,43 @@ static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp,
|
||||
|
||||
static int _vl_sv_adjusted_bit(const VerilatedDpiOpenVar* varp, int indx) {
|
||||
if (VL_UNLIKELY(indx < varp->low(0) || indx > varp->high(0))) {
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function packed index out of bounds; %d outside [%d:%d].\n",
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function packed index out of bounds; %d "
|
||||
"outside [%d:%d].\n",
|
||||
indx, varp->left(0), varp->right(0));
|
||||
return 0;
|
||||
}
|
||||
return indx - varp->low(0);
|
||||
}
|
||||
|
||||
/// Return pointer to simulator open array element, or NULL if outside range
|
||||
static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h,
|
||||
int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||
/// Return pointer to simulator open array element, or nullptr if outside range
|
||||
static void* _vl_svGetArrElemPtr(const svOpenArrayHandle h, int nargs, int indx1, int indx2,
|
||||
int indx3) VL_MT_SAFE {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(h);
|
||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return NULL;
|
||||
if (VL_UNLIKELY(!varp->isDpiStdLayout())) return nullptr;
|
||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||
return datap;
|
||||
}
|
||||
|
||||
/// Copy to user bit array from simulator open array
|
||||
static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||
static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int nargs,
|
||||
int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||
if (VL_UNLIKELY(!datap)) return;
|
||||
switch (varp->vltype()) {
|
||||
case VLVT_UINT8: d[0] = *(reinterpret_cast<CData*>(datap)); return;
|
||||
case VLVT_UINT8: d[0] = *(reinterpret_cast<CData*>(datap)); return;
|
||||
case VLVT_UINT16: d[0] = *(reinterpret_cast<SData*>(datap)); return;
|
||||
case VLVT_UINT32: d[0] = *(reinterpret_cast<IData*>(datap)); return;
|
||||
case VLVT_UINT64: {
|
||||
WData lwp[2]; VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||
d[0] = lwp[0]; d[1] = lwp[1];
|
||||
WData lwp[2];
|
||||
VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||
d[0] = lwp[0];
|
||||
d[1] = lwp[1];
|
||||
break;
|
||||
}
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
for (int i=0; i<VL_WORDS_I(varp->packed().elements()); ++i) d[i] = wdatap[i];
|
||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) d[i] = wdatap[i];
|
||||
return;
|
||||
}
|
||||
default:
|
||||
@@ -323,25 +306,38 @@ static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
}
|
||||
}
|
||||
/// Copy to user logic array from simulator open array
|
||||
static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||
static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int nargs,
|
||||
int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||
if (VL_UNLIKELY(!datap)) return;
|
||||
switch (varp->vltype()) {
|
||||
case VLVT_UINT8: d[0].aval = *(reinterpret_cast<CData*>(datap)); d[0].bval=0; return;
|
||||
case VLVT_UINT16: d[0].aval = *(reinterpret_cast<SData*>(datap)); d[0].bval=0; return;
|
||||
case VLVT_UINT32: d[0].aval = *(reinterpret_cast<IData*>(datap)); d[0].bval=0; return;
|
||||
case VLVT_UINT8:
|
||||
d[0].aval = *(reinterpret_cast<CData*>(datap));
|
||||
d[0].bval = 0;
|
||||
return;
|
||||
case VLVT_UINT16:
|
||||
d[0].aval = *(reinterpret_cast<SData*>(datap));
|
||||
d[0].bval = 0;
|
||||
return;
|
||||
case VLVT_UINT32:
|
||||
d[0].aval = *(reinterpret_cast<IData*>(datap));
|
||||
d[0].bval = 0;
|
||||
return;
|
||||
case VLVT_UINT64: {
|
||||
WData lwp[2]; VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||
d[0].aval = lwp[0]; d[0].bval=0;
|
||||
d[1].aval = lwp[1]; d[0].bval=0;
|
||||
WData lwp[2];
|
||||
VL_SET_WQ(lwp, *(reinterpret_cast<QData*>(datap)));
|
||||
d[0].aval = lwp[0];
|
||||
d[0].bval = 0;
|
||||
d[1].aval = lwp[1];
|
||||
d[0].bval = 0;
|
||||
break;
|
||||
}
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
for (int i=0; i<VL_WORDS_I(varp->packed().elements()); ++i) {
|
||||
d[i].aval = wdatap[i]; d[i].bval = 0;
|
||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) {
|
||||
d[i].aval = wdatap[i];
|
||||
d[i].bval = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
@@ -353,19 +349,19 @@ static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandl
|
||||
}
|
||||
|
||||
/// Copy to simulator open array from from user bit array
|
||||
static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int nargs, int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||
static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int nargs,
|
||||
int indx1, int indx2, int indx3) VL_MT_SAFE {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||
if (VL_UNLIKELY(!datap)) return;
|
||||
switch (varp->vltype()) {
|
||||
case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0]; return;
|
||||
case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0]; return;
|
||||
case VLVT_UINT16: *(reinterpret_cast<SData*>(datap)) = s[0]; return;
|
||||
case VLVT_UINT32: *(reinterpret_cast<IData*>(datap)) = s[0]; return;
|
||||
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1], s[0]); break;
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
for (int i=0; i<VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i];
|
||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i];
|
||||
return;
|
||||
}
|
||||
default:
|
||||
@@ -381,80 +377,82 @@ static void _vl_svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogic
|
||||
void* datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||
if (VL_UNLIKELY(!datap)) return;
|
||||
switch (varp->vltype()) {
|
||||
case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0].aval; return;
|
||||
case VLVT_UINT8: *(reinterpret_cast<CData*>(datap)) = s[0].aval; return;
|
||||
case VLVT_UINT16: *(reinterpret_cast<SData*>(datap)) = s[0].aval; return;
|
||||
case VLVT_UINT32: *(reinterpret_cast<IData*>(datap)) = s[0].aval; return;
|
||||
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1].aval, s[0].aval); break;
|
||||
case VLVT_UINT64:
|
||||
*(reinterpret_cast<QData*>(datap)) = _VL_SET_QII(s[1].aval, s[0].aval);
|
||||
break;
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
for (int i=0; i<VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i].aval;
|
||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i].aval;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
|
||||
varp->vltype());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/// Return bit from simulator open array
|
||||
static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s,
|
||||
int nargs, int indx1, int indx2, int indx3, int indx4) VL_MT_SAFE {
|
||||
static svBit _vl_svGetBitArrElem(const svOpenArrayHandle s, int nargs, int indx1, int indx2,
|
||||
int indx3, int indx4) VL_MT_SAFE {
|
||||
// One extra index supported, as need bit number
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||
void* datap;
|
||||
int lsb;
|
||||
if (varp->packed().elements()) {
|
||||
datap = _vl_sv_adjusted_datap(varp, nargs-1, indx1, indx2, indx3);
|
||||
lsb = _vl_sv_adjusted_bit(varp, ((nargs==1) ? indx1
|
||||
: (nargs==2) ? indx2
|
||||
: (nargs==3) ? indx3
|
||||
: indx4));
|
||||
datap = _vl_sv_adjusted_datap(varp, nargs - 1, indx1, indx2, indx3);
|
||||
lsb = _vl_sv_adjusted_bit(
|
||||
varp, ((nargs == 1) ? indx1 : (nargs == 2) ? indx2 : (nargs == 3) ? indx3 : indx4));
|
||||
} else {
|
||||
datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||
lsb = 0;
|
||||
}
|
||||
if (VL_UNLIKELY(!datap)) return 0;
|
||||
switch (varp->vltype()) {
|
||||
case VLVT_UINT8: return (*(reinterpret_cast<CData*>(datap)) >> lsb) & 1;
|
||||
case VLVT_UINT8: return (*(reinterpret_cast<CData*>(datap)) >> lsb) & 1;
|
||||
case VLVT_UINT16: return (*(reinterpret_cast<SData*>(datap)) >> lsb) & 1;
|
||||
case VLVT_UINT32: return (*(reinterpret_cast<IData*>(datap)) >> lsb) & 1;
|
||||
case VLVT_UINT64: return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & VL_ULL(1);
|
||||
case VLVT_UINT64:
|
||||
return (*(reinterpret_cast<QData*>(datap)) >> static_cast<QData>(lsb)) & 1ULL;
|
||||
case VLVT_WDATA: {
|
||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||
return VL_BITRSHIFT_W(wdatap, lsb) & 1;
|
||||
}
|
||||
default:
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
|
||||
varp->vltype());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/// Update simulator open array from bit
|
||||
static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value,
|
||||
int nargs, int indx1, int indx2, int indx3, int indx4) VL_MT_SAFE {
|
||||
static void _vl_svPutBitArrElem(const svOpenArrayHandle d, svBit value, int nargs, int indx1,
|
||||
int indx2, int indx3, int indx4) VL_MT_SAFE {
|
||||
// One extra index supported, as need bit number
|
||||
value &= 1; // Make sure clean
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
||||
void* datap;
|
||||
int lsb;
|
||||
if (varp->packed().elements()) {
|
||||
datap = _vl_sv_adjusted_datap(varp, nargs-1, indx1, indx2, indx3);
|
||||
lsb = _vl_sv_adjusted_bit(varp, ((nargs==1) ? indx1
|
||||
: (nargs==2) ? indx2
|
||||
: (nargs==3) ? indx3
|
||||
: indx4));
|
||||
datap = _vl_sv_adjusted_datap(varp, nargs - 1, indx1, indx2, indx3);
|
||||
lsb = _vl_sv_adjusted_bit(
|
||||
varp, ((nargs == 1) ? indx1 : (nargs == 2) ? indx2 : (nargs == 3) ? indx3 : indx4));
|
||||
} else {
|
||||
datap = _vl_sv_adjusted_datap(varp, nargs, indx1, indx2, indx3);
|
||||
lsb = 0;
|
||||
}
|
||||
if (VL_UNLIKELY(!datap)) return;
|
||||
switch (varp->vltype()) {
|
||||
case VLVT_UINT8: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<CData*>(datap)), value); return;
|
||||
case VLVT_UINT8: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<CData*>(datap)), value); return;
|
||||
case VLVT_UINT16: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<SData*>(datap)), value); return;
|
||||
case VLVT_UINT32: VL_ASSIGNBIT_II(-1, lsb, *(reinterpret_cast<IData*>(datap)), value); return;
|
||||
case VLVT_UINT64: VL_ASSIGNBIT_QI(-1, lsb, *(reinterpret_cast<QData*>(datap)), value); return;
|
||||
case VLVT_WDATA: VL_ASSIGNBIT_WI(-1, lsb, (reinterpret_cast<WDataOutP>(datap)), value); return;
|
||||
case VLVT_WDATA: VL_ASSIGNBIT_WI(-1, lsb, (reinterpret_cast<WDataOutP>(datap)), value); return;
|
||||
default:
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n", varp->vltype());
|
||||
_VL_SVDPI_WARN("%%Warning: DPI svOpenArrayHandle function unsupported datatype (%d).\n",
|
||||
varp->vltype());
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -470,10 +468,17 @@ void* svGetArrElemPtr(const svOpenArrayHandle h, int indx1, ...) {
|
||||
// va_arg is a macro, so need temporaries as used below
|
||||
switch (varp->udims()) {
|
||||
case 1: datap = _vl_svGetArrElemPtr(h, 1, indx1, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
datap = _vl_svGetArrElemPtr(h, 2, indx1, indx2, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
datap = _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
|
||||
break;
|
||||
}
|
||||
default: datap = _vl_svGetArrElemPtr(h, -1, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
@@ -489,116 +494,134 @@ void* svGetArrElemPtr3(const svOpenArrayHandle h, int indx1, int indx2, int indx
|
||||
return _vl_svGetArrElemPtr(h, 3, indx1, indx2, indx3);
|
||||
}
|
||||
|
||||
void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, ...) {
|
||||
void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, ...) {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
||||
va_list ap;
|
||||
va_start(ap, indx1);
|
||||
switch (varp->udims()) {
|
||||
case 1: _vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
_vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
_vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
_vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
_vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||
break;
|
||||
}
|
||||
default: _vl_svPutBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1) {
|
||||
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1) {
|
||||
_vl_svPutBitArrElemVecVal(d, s, 1, indx1, 0, 0);
|
||||
}
|
||||
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2) {
|
||||
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1,
|
||||
int indx2) {
|
||||
_vl_svPutBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||
}
|
||||
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s, int indx1, int indx2,
|
||||
int indx3) {
|
||||
_vl_svPutBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||
}
|
||||
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, ...) {
|
||||
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1, ...) {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(d);
|
||||
va_list ap;
|
||||
va_start(ap, indx1);
|
||||
switch (varp->udims()) {
|
||||
case 1: _vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
_vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
_vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
_vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
_vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||
break;
|
||||
}
|
||||
default: _vl_svPutLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1) {
|
||||
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1) {
|
||||
_vl_svPutLogicArrElemVecVal(d, s, 1, indx1, 0, 0);
|
||||
}
|
||||
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2) {
|
||||
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1,
|
||||
int indx2) {
|
||||
_vl_svPutLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||
}
|
||||
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s, int indx1,
|
||||
int indx2, int indx3) {
|
||||
_vl_svPutLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// From simulator storage into user space
|
||||
|
||||
void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...) {
|
||||
void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, ...) {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||
va_list ap;
|
||||
va_start(ap, indx1);
|
||||
switch (varp->udims()) {
|
||||
case 1: _vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
_vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
_vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
_vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
_vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||
break;
|
||||
}
|
||||
default: _vl_svGetBitArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1) {
|
||||
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1) {
|
||||
_vl_svGetBitArrElemVecVal(d, s, 1, indx1, 0, 0);
|
||||
}
|
||||
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2) {
|
||||
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_vl_svGetBitArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||
}
|
||||
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3) {
|
||||
_vl_svGetBitArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||
}
|
||||
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...) {
|
||||
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, ...) {
|
||||
const VerilatedDpiOpenVar* varp = _vl_openhandle_varp(s);
|
||||
va_list ap;
|
||||
va_start(ap, indx1);
|
||||
switch (varp->udims()) {
|
||||
case 1: _vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
_vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
_vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
_vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
_vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||
break;
|
||||
}
|
||||
default: _vl_svGetLogicArrElemVecVal(d, s, -1, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
}
|
||||
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1) {
|
||||
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1) {
|
||||
_vl_svGetLogicArrElemVecVal(d, s, 1, indx1, 0, 0);
|
||||
}
|
||||
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2) {
|
||||
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_vl_svGetLogicArrElemVecVal(d, s, 2, indx1, indx2, 0);
|
||||
}
|
||||
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3) {
|
||||
_vl_svGetLogicArrElemVecVal(d, s, 3, indx1, indx2, indx3);
|
||||
}
|
||||
|
||||
@@ -609,12 +632,24 @@ svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
va_start(ap, indx1);
|
||||
switch (varp->udims()) {
|
||||
case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); break; }
|
||||
case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int);
|
||||
out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
int indx4 = va_arg(ap, int);
|
||||
out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4);
|
||||
break;
|
||||
}
|
||||
default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
@@ -637,12 +672,24 @@ svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
va_start(ap, indx1);
|
||||
switch (varp->udims()) {
|
||||
case 1: out = _vl_svGetBitArrElem(s, 1, indx1, 0, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0); break; }
|
||||
case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int);
|
||||
out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
out = _vl_svGetBitArrElem(s, 2, indx1, indx2, 0, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
out = _vl_svGetBitArrElem(s, 3, indx1, indx2, indx3, 0);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
int indx4 = va_arg(ap, int);
|
||||
out = _vl_svGetBitArrElem(s, 4, indx1, indx2, indx3, indx4);
|
||||
break;
|
||||
}
|
||||
default: out = _vl_svGetBitArrElem(s, -1, 0, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
@@ -667,12 +714,24 @@ void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) {
|
||||
va_start(ap, indx1);
|
||||
switch (varp->udims()) {
|
||||
case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
_vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
_vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); break; }
|
||||
case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int);
|
||||
_vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
_vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
_vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
int indx4 = va_arg(ap, int);
|
||||
_vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4);
|
||||
break;
|
||||
}
|
||||
default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
@@ -693,12 +752,24 @@ void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...)
|
||||
va_start(ap, indx1);
|
||||
switch (varp->udims()) {
|
||||
case 1: _vl_svPutBitArrElem(d, value, 1, indx1, 0, 0, 0); break;
|
||||
case 2: { int indx2=va_arg(ap,int);
|
||||
_vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0); break; }
|
||||
case 3: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int);
|
||||
_vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0); break; }
|
||||
case 4: { int indx2=va_arg(ap,int); int indx3=va_arg(ap,int); int indx4=va_arg(ap,int);
|
||||
_vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4); break; }
|
||||
case 2: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
_vl_svPutBitArrElem(d, value, 2, indx1, indx2, 0, 0);
|
||||
break;
|
||||
}
|
||||
case 3: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
_vl_svPutBitArrElem(d, value, 3, indx1, indx2, indx3, 0);
|
||||
break;
|
||||
}
|
||||
case 4: {
|
||||
int indx2 = va_arg(ap, int);
|
||||
int indx3 = va_arg(ap, int);
|
||||
int indx4 = va_arg(ap, int);
|
||||
_vl_svPutBitArrElem(d, value, 4, indx1, indx2, indx3, indx4);
|
||||
break;
|
||||
}
|
||||
default: _vl_svPutBitArrElem(d, value, -1, 0, 0, 0, 0); break; // Will error
|
||||
}
|
||||
va_end(ap);
|
||||
@@ -707,13 +778,12 @@ void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
svPutBitArrElem1(d, value, indx1);
|
||||
}
|
||||
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value,
|
||||
int indx1, int indx2) {
|
||||
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
svPutBitArrElem2(d, value, indx1, indx2);
|
||||
}
|
||||
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value,
|
||||
int indx1, int indx2, int indx3) {
|
||||
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2,
|
||||
int indx3) {
|
||||
// Verilator doesn't support X/Z so can just call Bit version
|
||||
svPutBitArrElem3(d, value, indx1, indx2, indx3);
|
||||
}
|
||||
@@ -722,7 +792,10 @@ void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value,
|
||||
// Functions for working with DPI context
|
||||
|
||||
svScope svGetScope() {
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return NULL; }
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) {
|
||||
_VL_SVDPI_CONTEXT_WARN();
|
||||
return nullptr;
|
||||
}
|
||||
// NOLINTNEXTLINE(google-readability-casting)
|
||||
return (svScope)(Verilated::dpiScope());
|
||||
}
|
||||
@@ -746,16 +819,19 @@ svScope svGetScopeFromName(const char* scopeName) {
|
||||
}
|
||||
|
||||
int svPutUserData(const svScope scope, void* userKey, void* userData) {
|
||||
VerilatedImp::userInsert(scope,userKey,userData);
|
||||
VerilatedImp::userInsert(scope, userKey, userData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* svGetUserData(const svScope scope, void* userKey) {
|
||||
return VerilatedImp::userFind(scope,userKey);
|
||||
return VerilatedImp::userFind(scope, userKey);
|
||||
}
|
||||
|
||||
int svGetCallerInfo(const char** fileNamepp, int *lineNumberp) {
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return false; }
|
||||
int svGetCallerInfo(const char** fileNamepp, int* lineNumberp) {
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) {
|
||||
_VL_SVDPI_CONTEXT_WARN();
|
||||
return false;
|
||||
}
|
||||
if (VL_LIKELY(fileNamepp)) *fileNamepp = Verilated::dpiFilenamep(); // thread local
|
||||
if (VL_LIKELY(lineNumberp)) *lineNumberp = Verilated::dpiLineno(); // thread local
|
||||
return true;
|
||||
|
||||
+33
-19
@@ -32,45 +32,59 @@
|
||||
//===================================================================
|
||||
// SETTING OPERATORS
|
||||
|
||||
/// Return WData from svBitVecVal
|
||||
/// Convert svBitVecVal to Verilator internal data
|
||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, const svBitVecVal* lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
|
||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
||||
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i];
|
||||
owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits);
|
||||
}
|
||||
/// Return svBitVecVal from WData
|
||||
static inline QData VL_SET_Q_SVBV(const svBitVecVal* lwp) VL_MT_SAFE {
|
||||
return _VL_SET_QII(lwp[1], lwp[0]);
|
||||
}
|
||||
static inline IData VL_SET_I_SVBV(const svBitVecVal* lwp) VL_MT_SAFE { return lwp[0]; }
|
||||
|
||||
/// Convert Verilator internal data to svBitVecVal
|
||||
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i];
|
||||
owp[words-1] = lwp[words-1] & VL_MASK_I(obits);
|
||||
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i];
|
||||
owp[words - 1] = lwp[words - 1] & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_SVBV_I(int, svBitVecVal* owp, IData ld) VL_MT_SAFE { owp[0] = ld; }
|
||||
static inline void VL_SET_SVBV_Q(int, svBitVecVal* owp, QData ld) VL_MT_SAFE {
|
||||
VL_SET_WQ(owp, ld);
|
||||
}
|
||||
|
||||
/// Convert svLogicVecVal to/from WData
|
||||
/// Convert svLogicVecVal to Verilator internal data
|
||||
/// Note these functions ignore X/Z in svLogicVecVal
|
||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words-1; ++i) owp[i]=lwp[i].aval;
|
||||
owp[words-1] = lwp[words-1].aval & VL_MASK_I(obits);
|
||||
for (int i = 0; i < words - 1; ++i) owp[i] = lwp[i].aval;
|
||||
owp[words - 1] = lwp[words - 1].aval & VL_MASK_I(obits);
|
||||
}
|
||||
static inline QData VL_SET_Q_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||
return _VL_SET_QII(lwp[1].aval, lwp[0].aval);
|
||||
}
|
||||
static inline IData VL_SET_I_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE {
|
||||
return lwp[0].aval;
|
||||
}
|
||||
static inline IData VL_SET_I_SVLV(const svLogicVecVal* lwp) VL_MT_SAFE { return lwp[0].aval; }
|
||||
|
||||
/// Convert Verilator internal data to svLogicVecVal
|
||||
/// Note these functions never create X/Z in svLogicVecVal
|
||||
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) VL_MT_SAFE {
|
||||
int words = VL_WORDS_I(obits);
|
||||
for (int i=0; i<words; ++i) owp[i].bval=0;
|
||||
for (int i=0; i<words-1; ++i) owp[i].aval=lwp[i];
|
||||
owp[words-1].aval = lwp[words-1] & VL_MASK_I(obits);
|
||||
for (int i = 0; i < words; ++i) owp[i].bval = 0;
|
||||
for (int i = 0; i < words - 1; ++i) owp[i].aval = lwp[i];
|
||||
owp[words - 1].aval = lwp[words - 1] & VL_MASK_I(obits);
|
||||
}
|
||||
static inline void VL_SET_SVLV_I(int, svLogicVecVal* owp, IData ld) VL_MT_SAFE {
|
||||
owp[0].aval=ld; owp[0].bval=0;
|
||||
owp[0].aval = ld;
|
||||
owp[0].bval = 0;
|
||||
}
|
||||
static inline void VL_SET_SVLV_Q(int, svLogicVecVal* owp, QData ld) VL_MT_SAFE {
|
||||
WData lwp[2]; VL_SET_WQ(lwp,ld);
|
||||
owp[0].aval=lwp[0]; owp[0].bval=0;
|
||||
owp[1].aval=lwp[1]; owp[1].bval=0;
|
||||
WData lwp[2];
|
||||
VL_SET_WQ(lwp, ld);
|
||||
owp[0].aval = lwp[0];
|
||||
owp[0].bval = 0;
|
||||
owp[1].aval = lwp[1];
|
||||
owp[1].bval = 0;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
+138
-100
@@ -17,13 +17,14 @@
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
// clang-format off
|
||||
|
||||
#define __STDC_LIMIT_MACROS // UINT64_MAX
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_fst_c.h"
|
||||
|
||||
// GTKWave configuration
|
||||
#ifdef VL_TRACE_THREADED
|
||||
#ifdef VL_TRACE_FST_WRITER_THREAD
|
||||
# define HAVE_LIBPTHREAD
|
||||
# define FST_WRITER_PARALLEL
|
||||
#endif
|
||||
@@ -35,116 +36,111 @@
|
||||
#include "gtkwave/lz4.c"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
#include <fcntl.h>
|
||||
#include <iterator>
|
||||
#include <sstream>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <stdint.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// clang-format on
|
||||
|
||||
class VerilatedFstCallInfo {
|
||||
protected:
|
||||
friend class VerilatedFst;
|
||||
VerilatedFstCallback_t m_initcb; ///< Initialization Callback function
|
||||
VerilatedFstCallback_t m_fullcb; ///< Full Dumping Callback function
|
||||
VerilatedFstCallback_t m_changecb; ///< Incremental Dumping Callback function
|
||||
void* m_userthis; ///< Fake "this" for caller
|
||||
vluint32_t m_code; ///< Starting code number
|
||||
// CONSTRUCTORS
|
||||
VerilatedFstCallInfo(VerilatedFstCallback_t icb, VerilatedFstCallback_t fcb,
|
||||
VerilatedFstCallback_t changecb, void* ut)
|
||||
: m_initcb(icb)
|
||||
, m_fullcb(fcb)
|
||||
, m_changecb(changecb)
|
||||
, m_userthis(ut)
|
||||
, m_code(1) {}
|
||||
~VerilatedFstCallInfo() {}
|
||||
};
|
||||
//=============================================================================
|
||||
// Specialization of the generics for this trace format
|
||||
|
||||
#define VL_DERIVED_T VerilatedFst
|
||||
#include "verilated_trace_imp.cpp"
|
||||
#undef VL_DERIVED_T
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedFst
|
||||
|
||||
VerilatedFst::VerilatedFst(void* fst)
|
||||
: m_fst(fst)
|
||||
, m_fullDump(true)
|
||||
, m_nextCode(1)
|
||||
, m_scopeEscape('.') {
|
||||
m_valueStrBuffer.reserve(64 + 1); // Need enough room for quad
|
||||
: m_fst{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);
|
||||
}
|
||||
|
||||
void VerilatedFst::open(const char* filename) VL_MT_UNSAFE {
|
||||
m_assertOne.check();
|
||||
m_fst = fstWriterCreate(filename, 1);
|
||||
fstWriterSetPackType(m_fst, FST_WR_PT_LZ4);
|
||||
#ifdef VL_TRACE_THREADED
|
||||
fstWriterSetTimescaleFromString(m_fst, timeResStr().c_str()); // lintok-begin-on-ref
|
||||
#ifdef VL_TRACE_FST_WRITER_THREAD
|
||||
fstWriterSetParallelMode(m_fst, 1);
|
||||
#endif
|
||||
m_curScope.clear();
|
||||
m_nextCode = 1;
|
||||
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
||||
VerilatedFstCallInfo* cip = m_callbacks[ent];
|
||||
cip->m_code = m_nextCode;
|
||||
// Initialize; callbacks will call decl* which update m_nextCode
|
||||
(cip->m_initcb)(this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
m_curScope.clear();
|
||||
|
||||
VerilatedTrace<VerilatedFst>::traceInit();
|
||||
|
||||
// Clear the scope stack
|
||||
std::list<std::string>::iterator it = m_curScope.begin();
|
||||
auto it = m_curScope.begin();
|
||||
while (it != m_curScope.end()) {
|
||||
fstWriterSetUpscope(m_fst);
|
||||
it = m_curScope.erase(it);
|
||||
}
|
||||
|
||||
// convert m_code2symbol into an array for fast lookup
|
||||
if (!m_symbolp) {
|
||||
m_symbolp = new fstHandle[nextCode()];
|
||||
for (const auto& i : m_code2symbol) m_symbolp[i.first] = i.second;
|
||||
}
|
||||
m_code2symbol.clear();
|
||||
|
||||
// Allocate string buffer for arrays
|
||||
if (!m_strbuf) { m_strbuf = new char[maxBits() + 32]; }
|
||||
}
|
||||
|
||||
void VerilatedFst::module(const std::string& name) {
|
||||
m_module = name;
|
||||
void VerilatedFst::close() {
|
||||
m_assertOne.check();
|
||||
VerilatedTrace<VerilatedFst>::close();
|
||||
fstWriterClose(m_fst);
|
||||
m_fst = nullptr;
|
||||
}
|
||||
|
||||
void VerilatedFst::flush() {
|
||||
VerilatedTrace<VerilatedFst>::flush();
|
||||
fstWriterFlushContext(m_fst);
|
||||
}
|
||||
|
||||
void VerilatedFst::emitTimeChange(vluint64_t timeui) { fstWriterEmitTimeChange(m_fst, timeui); }
|
||||
|
||||
//=============================================================================
|
||||
// Decl
|
||||
|
||||
void VerilatedFst::declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
|
||||
unsigned int minValbits,
|
||||
const char** itemNamesp, const char** itemValuesp) {
|
||||
fstEnumHandle enumNum = fstWriterCreateEnumTable(m_fst, name, elements,
|
||||
minValbits, itemNamesp, itemValuesp);
|
||||
unsigned int minValbits, const char** itemNamesp,
|
||||
const char** itemValuesp) {
|
||||
fstEnumHandle enumNum
|
||||
= fstWriterCreateEnumTable(m_fst, name, elements, minValbits, itemNamesp, itemValuesp);
|
||||
m_local2fstdtype[dtypenum] = enumNum;
|
||||
}
|
||||
|
||||
void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, vluint32_t len,
|
||||
vluint32_t bits) {
|
||||
void VerilatedFst::declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
const int bits = ((msb > lsb) ? (msb - lsb) : (lsb - msb)) + 1;
|
||||
|
||||
// Make sure deduplicate tracking increments for future declarations
|
||||
int codesNeeded = 1 + int(bits / 32);
|
||||
//Not supported: if (tri) codesNeeded *= 2; // Space in change array for __en signals
|
||||
m_nextCode = std::max(m_nextCode, code + codesNeeded);
|
||||
VerilatedTrace<VerilatedFst>::declCode(code, bits, false);
|
||||
|
||||
std::pair<Code2SymbolType::iterator, bool> p
|
||||
= m_code2symbol.insert(std::make_pair(code, static_cast<fstHandle>(NULL)));
|
||||
std::istringstream nameiss(name);
|
||||
std::istream_iterator<std::string> beg(nameiss), end;
|
||||
std::istream_iterator<std::string> beg(nameiss);
|
||||
std::istream_iterator<std::string> end;
|
||||
std::list<std::string> tokens(beg, end); // Split name
|
||||
std::string symbol_name(tokens.back());
|
||||
tokens.pop_back(); // Remove symbol name from hierarchy
|
||||
tokens.insert(tokens.begin(), m_module); // Add current module to the hierarchy
|
||||
tokens.insert(tokens.begin(), moduleName()); // Add current module to the hierarchy
|
||||
|
||||
// Find point where current and new scope diverge
|
||||
std::list<std::string>::iterator cur_it = m_curScope.begin();
|
||||
std::list<std::string>::iterator new_it = tokens.begin();
|
||||
auto cur_it = m_curScope.begin();
|
||||
auto new_it = tokens.begin();
|
||||
while (cur_it != m_curScope.end() && new_it != tokens.end()) {
|
||||
if (*cur_it != *new_it)
|
||||
break;
|
||||
if (*cur_it != *new_it) break;
|
||||
++cur_it;
|
||||
++new_it;
|
||||
}
|
||||
@@ -157,7 +153,7 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f
|
||||
|
||||
// Follow the hierarchy of the new variable from the common scope point
|
||||
while (new_it != tokens.end()) {
|
||||
fstWriterSetScope(m_fst, FST_ST_VCD_SCOPE, new_it->c_str(), NULL);
|
||||
fstWriterSetScope(m_fst, FST_ST_VCD_SCOPE, new_it->c_str(), nullptr);
|
||||
m_curScope.push_back(*new_it);
|
||||
new_it = tokens.erase(new_it);
|
||||
}
|
||||
@@ -171,49 +167,91 @@ void VerilatedFst::declSymbol(vluint32_t code, const char* name, int dtypenum, f
|
||||
fstEnumHandle enumNum = m_local2fstdtype[dtypenum];
|
||||
fstWriterEmitEnumTableRef(m_fst, enumNum);
|
||||
}
|
||||
if (p.second) { // New
|
||||
p.first->second = fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), 0);
|
||||
assert(p.first->second);
|
||||
|
||||
const auto it = vlstd::as_const(m_code2symbol).find(code);
|
||||
if (it == m_code2symbol.end()) { // New
|
||||
m_code2symbol[code]
|
||||
= fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), 0);
|
||||
} else { // Alias
|
||||
fstWriterCreateVar(m_fst, vartype, vardir, len, name_str.c_str(), p.first->second);
|
||||
fstWriterCreateVar(m_fst, vartype, vardir, bits, name_str.c_str(), it->second);
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Callbacks
|
||||
|
||||
void VerilatedFst::addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
|
||||
VerilatedFstCallback_t changecb, void* userthis) VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
if (VL_UNLIKELY(isOpen())) {
|
||||
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
|
||||
+ " called with already open file");
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
}
|
||||
VerilatedFstCallInfo* cip = new VerilatedFstCallInfo(initcb, fullcb, changecb, userthis);
|
||||
m_callbacks.push_back(cip);
|
||||
void VerilatedFst::declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 0, 0);
|
||||
}
|
||||
void VerilatedFst::declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||
}
|
||||
void VerilatedFst::declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||
}
|
||||
void VerilatedFst::declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, msb, lsb);
|
||||
}
|
||||
void VerilatedFst::declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum) {
|
||||
declare(code, name, dtypenum, vardir, vartype, array, arraynum, 63, 0);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Dumping
|
||||
// Note: emit* are only ever called from one place (full* in
|
||||
// verilated_trace_imp.cpp, which is included in this file at the top),
|
||||
// so always inline them.
|
||||
|
||||
void VerilatedFst::dump(vluint64_t timeui) {
|
||||
if (!isOpen()) return;
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
m_fullDump = false; // No more need for next dump to be full
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
||||
VerilatedFstCallInfo* cip = m_callbacks[ent];
|
||||
(cip->m_fullcb)(this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
return;
|
||||
}
|
||||
fstWriterEmitTimeChange(m_fst, timeui);
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ++ent) {
|
||||
VerilatedFstCallInfo* cip = m_callbacks[ent];
|
||||
(cip->m_changecb)(this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFst::emitBit(vluint32_t code, CData newval) {
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], newval ? "1" : "0");
|
||||
}
|
||||
|
||||
//********************************************************************
|
||||
// Local Variables:
|
||||
// End:
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFst::emitCData(vluint32_t code, CData newval, int bits) {
|
||||
char buf[VL_BYTESIZE];
|
||||
cvtCDataToStr(buf, newval << (VL_BYTESIZE - bits));
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFst::emitSData(vluint32_t code, SData newval, int bits) {
|
||||
char buf[VL_SHORTSIZE];
|
||||
cvtSDataToStr(buf, newval << (VL_SHORTSIZE - bits));
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFst::emitIData(vluint32_t code, IData newval, int bits) {
|
||||
char buf[VL_IDATASIZE];
|
||||
cvtIDataToStr(buf, newval << (VL_IDATASIZE - bits));
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFst::emitQData(vluint32_t code, QData newval, int bits) {
|
||||
char buf[VL_QUADSIZE];
|
||||
cvtQDataToStr(buf, newval << (VL_QUADSIZE - bits));
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], buf);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFst::emitWData(vluint32_t code, const WData* newvalp, int bits) {
|
||||
int words = VL_WORDS_I(bits);
|
||||
char* wp = m_strbuf;
|
||||
// Convert the most significant word
|
||||
const int bitsInMSW = VL_BITBIT_E(bits) ? VL_BITBIT_E(bits) : VL_EDATASIZE;
|
||||
cvtEDataToStr(wp, newvalp[--words] << (VL_EDATASIZE - bitsInMSW));
|
||||
wp += bitsInMSW;
|
||||
// Convert the remaining words
|
||||
while (words > 0) {
|
||||
cvtEDataToStr(wp, newvalp[--words]);
|
||||
wp += VL_EDATASIZE;
|
||||
}
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf);
|
||||
}
|
||||
|
||||
VL_ATTR_ALWINLINE
|
||||
void VerilatedFst::emitDouble(vluint32_t code, double newval) {
|
||||
fstWriterEmitValueChange(m_fst, m_symbolp[code], &newval);
|
||||
}
|
||||
|
||||
+79
-142
@@ -20,8 +20,8 @@
|
||||
#ifndef _VERILATED_FST_C_H_
|
||||
#define _VERILATED_FST_C_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_trace.h"
|
||||
|
||||
#include "gtkwave/fstapi.h"
|
||||
|
||||
@@ -30,163 +30,98 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class VerilatedFst;
|
||||
class VerilatedFstCallInfo;
|
||||
typedef void (*VerilatedFstCallback_t)(VerilatedFst* vcdp, void* userthis, vluint32_t code);
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedFst
|
||||
/// Base class to create a Verilator FST dump
|
||||
/// This is an internally used class - see VerilatedFstC for what to call from applications
|
||||
|
||||
class VerilatedFst {
|
||||
class VerilatedFst : public VerilatedTrace<VerilatedFst> {
|
||||
private:
|
||||
// Give the superclass access to private bits (to avoid virtual functions)
|
||||
friend class VerilatedTrace<VerilatedFst>;
|
||||
|
||||
//=========================================================================
|
||||
// FST specific internals
|
||||
|
||||
typedef std::map<vluint32_t, fstHandle> Code2SymbolType;
|
||||
typedef std::map<int, fstEnumHandle> Local2FstDtype;
|
||||
typedef std::vector<VerilatedFstCallInfo*> CallbackVec;
|
||||
private:
|
||||
|
||||
void* m_fst;
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
bool m_fullDump;
|
||||
vluint32_t m_nextCode; ///< Next code number to assign
|
||||
char m_scopeEscape;
|
||||
std::string m_module;
|
||||
CallbackVec m_callbacks; ///< Routines to perform dumping
|
||||
Code2SymbolType m_code2symbol;
|
||||
Local2FstDtype 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
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFst);
|
||||
void declSymbol(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum, vluint32_t len, vluint32_t bits);
|
||||
// helpers
|
||||
std::vector<char> m_valueStrBuffer;
|
||||
void declare(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||
|
||||
protected:
|
||||
//=========================================================================
|
||||
// Implementation of VerilatedTrace interface
|
||||
|
||||
// Implementations of protected virtual methods for VerilatedTrace
|
||||
virtual void emitTimeChange(vluint64_t timeui) override;
|
||||
|
||||
// Hooks called from VerilatedTrace
|
||||
virtual bool preFullDump() override { return isOpen(); }
|
||||
virtual bool preChangeDump() override { return isOpen(); }
|
||||
|
||||
// Implementations of duck-typed methods for VerilatedTrace. These are
|
||||
// called from only one place (namely full*) so always inline them.
|
||||
inline void emitBit(vluint32_t code, CData newval);
|
||||
inline void emitCData(vluint32_t code, CData newval, int bits);
|
||||
inline void emitSData(vluint32_t code, SData newval, int bits);
|
||||
inline void emitIData(vluint32_t code, IData newval, int bits);
|
||||
inline void emitQData(vluint32_t code, QData newval, int bits);
|
||||
inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
|
||||
inline void emitDouble(vluint32_t code, double newval);
|
||||
|
||||
public:
|
||||
explicit VerilatedFst(void* fst=NULL);
|
||||
~VerilatedFst() { if (m_fst == NULL) { fstWriterClose(m_fst); } }
|
||||
void changeThread() { m_assertOne.changeThread(); }
|
||||
bool isOpen() const { return m_fst != NULL; }
|
||||
//=========================================================================
|
||||
// External interface to client code
|
||||
|
||||
explicit VerilatedFst(void* fst = nullptr);
|
||||
~VerilatedFst();
|
||||
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const char* filename) VL_MT_UNSAFE;
|
||||
void flush() VL_MT_UNSAFE { fstWriterFlushContext(m_fst); }
|
||||
void close() VL_MT_UNSAFE {
|
||||
m_assertOne.check();
|
||||
fstWriterClose(m_fst);
|
||||
m_fst = NULL;
|
||||
}
|
||||
void set_time_unit(const char* unitp) { fstWriterSetTimescaleFromString(m_fst, unitp); }
|
||||
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
|
||||
/// Close the file
|
||||
void close() VL_MT_UNSAFE;
|
||||
/// Flush any remaining data to this file
|
||||
void flush() VL_MT_UNSAFE;
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_fst != nullptr; }
|
||||
|
||||
void set_time_resolution(const char* unitp) { if (unitp) {} }
|
||||
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
|
||||
//=========================================================================
|
||||
// Internal interface to Verilator generated code
|
||||
|
||||
// double timescaleToDouble(const char* unitp);
|
||||
// std::string doubleToTimescale(double value);
|
||||
|
||||
/// Change character that splits scopes. Note whitespace are ALWAYS escapes.
|
||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
||||
/// Is this an escape?
|
||||
bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; }
|
||||
/// Inside dumping routines, called each cycle to make the dump
|
||||
void dump(vluint64_t timeui);
|
||||
/// Inside dumping routines, declare callbacks for tracings
|
||||
void addCallback(VerilatedFstCallback_t initcb, VerilatedFstCallback_t fullcb,
|
||||
VerilatedFstCallback_t changecb,
|
||||
void* userthis) VL_MT_UNSAFE_ONE;
|
||||
|
||||
/// Inside dumping routines, declare a module
|
||||
void module(const std::string& name);
|
||||
/// Inside dumping routines, declare a data type
|
||||
void declDTypeEnum(int dtypenum, const char* name, vluint32_t elements,
|
||||
unsigned int minValbits,
|
||||
const char** itemNamesp, const char** itemValuesp);
|
||||
unsigned int minValbits, const char** itemNamesp, const char** itemValuesp);
|
||||
|
||||
/// Inside dumping routines, declare a signal
|
||||
void declBit(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 1);
|
||||
}
|
||||
void declBus(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum, int msb, int lsb) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
||||
msb - lsb + 1);
|
||||
}
|
||||
void declDouble(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 2, 64);
|
||||
}
|
||||
void declFloat(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, 1, 32);
|
||||
}
|
||||
void declQuad(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum, int msb, int lsb) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
||||
msb - lsb + 1);
|
||||
}
|
||||
void declArray(vluint32_t code, const char* name,
|
||||
int dtypenum, fstVarDir vardir, fstVarType vartype,
|
||||
bool array, int arraynum, int msb, int lsb) {
|
||||
declSymbol(code, name, dtypenum, vardir, vartype, array, arraynum, msb - lsb + 1,
|
||||
msb - lsb + 1);
|
||||
}
|
||||
|
||||
/// Inside dumping routines, dump one signal if it has changed
|
||||
void chgBit(vluint32_t code, const vluint32_t newval) {
|
||||
fstWriterEmitValueChange(m_fst, m_code2symbol[code], newval ? "1" : "0");
|
||||
}
|
||||
void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||
fstWriterEmitValueChange32(m_fst, m_code2symbol[code], bits, newval);
|
||||
}
|
||||
void chgDouble(vluint32_t code, const double newval) {
|
||||
double val = newval;
|
||||
fstWriterEmitValueChange(m_fst, m_code2symbol[code], &val);
|
||||
}
|
||||
void chgFloat(vluint32_t code, const float newval) {
|
||||
double val = (double)newval;
|
||||
fstWriterEmitValueChange(m_fst, m_code2symbol[code], &val);
|
||||
}
|
||||
void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
||||
fstWriterEmitValueChange64(m_fst, m_code2symbol[code], bits, newval);
|
||||
}
|
||||
void chgArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
fstWriterEmitValueChangeVec32(m_fst, m_code2symbol[code], bits, newval);
|
||||
}
|
||||
|
||||
void fullBit(vluint32_t code, const vluint32_t newval) {
|
||||
chgBit(code, newval); }
|
||||
void fullBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||
chgBus(code, newval, bits); }
|
||||
void fullDouble(vluint32_t code, const double newval) {
|
||||
chgDouble(code, newval); }
|
||||
void fullFloat(vluint32_t code, const float newval) {
|
||||
chgFloat(code, newval); }
|
||||
void fullQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
||||
chgQuad(code, newval, bits); }
|
||||
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
chgArray(code, newval, bits); }
|
||||
|
||||
void declTriBit(vluint32_t code, const char* name, int arraynum);
|
||||
void declTriBus(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declTriQuad(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declTriArray(vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
|
||||
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
|
||||
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
|
||||
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits);
|
||||
void fullBitX(vluint32_t code);
|
||||
void fullBusX(vluint32_t code, int bits);
|
||||
void fullQuadX(vluint32_t code, int bits);
|
||||
void fullArrayX(vluint32_t code, int bits);
|
||||
void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
|
||||
void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
|
||||
void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint32_t newtri, int bits);
|
||||
void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits);
|
||||
void declBit(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
void declBus(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||
void declArray(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum, int msb, int lsb);
|
||||
void declDouble(vluint32_t code, const char* name, int dtypenum, fstVarDir vardir,
|
||||
fstVarType vartype, bool array, int arraynum);
|
||||
};
|
||||
|
||||
// Declare specialization here as it's used in VerilatedFstC just below
|
||||
template <> void VerilatedTrace<VerilatedFst>::dump(vluint64_t timeui);
|
||||
template <> void VerilatedTrace<VerilatedFst>::set_time_unit(const char* unitp);
|
||||
template <> void VerilatedTrace<VerilatedFst>::set_time_unit(const std::string& unit);
|
||||
template <> void VerilatedTrace<VerilatedFst>::set_time_resolution(const char* unitp);
|
||||
template <> void VerilatedTrace<VerilatedFst>::set_time_resolution(const std::string& unit);
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedFstC
|
||||
/// Create a FST dump file in C standalone (no SystemC) simulations.
|
||||
@@ -198,12 +133,14 @@ class VerilatedFstC {
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedFstC);
|
||||
|
||||
public:
|
||||
explicit VerilatedFstC(void* filep=NULL) : m_sptrace(filep) {}
|
||||
explicit VerilatedFstC(void* filep = nullptr)
|
||||
: m_sptrace{filep} {}
|
||||
~VerilatedFstC() { close(); }
|
||||
/// Routines can only be called from one thread; allow next call from different thread
|
||||
void changeThread() { spTrace()->changeThread(); }
|
||||
public:
|
||||
|
||||
// ACCESSORS
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_sptrace.isOpen(); }
|
||||
@@ -222,13 +159,13 @@ public:
|
||||
void dump(vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||
void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||
/// Set time units (s/ms, defaults to ns)
|
||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
||||
/// For Verilated models, these propage from the Verilated default --timeunit
|
||||
void set_time_unit(const char* unitp) { m_sptrace.set_time_unit(unitp); }
|
||||
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
|
||||
void set_time_unit(const std::string& unit) { m_sptrace.set_time_unit(unit); }
|
||||
/// Set time resolution (s/ms, defaults to ns)
|
||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
||||
/// For Verilated models, these propage from the Verilated default --timeunit
|
||||
void set_time_resolution(const char* unitp) { m_sptrace.set_time_resolution(unitp); }
|
||||
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
|
||||
void set_time_resolution(const std::string& unit) { m_sptrace.set_time_resolution(unit); }
|
||||
|
||||
/// Internal class access
|
||||
inline VerilatedFst* spTrace() { return &m_sptrace; };
|
||||
|
||||
+83
-50
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <deque>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
//===================================================================
|
||||
@@ -54,36 +55,39 @@ class VlReadMem {
|
||||
public:
|
||||
VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end);
|
||||
~VlReadMem();
|
||||
bool isOpen() const { return m_fp != NULL; }
|
||||
bool isOpen() const { return m_fp != nullptr; }
|
||||
int linenum() const { return m_linenum; }
|
||||
bool get(QData& addrr, std::string& valuer);
|
||||
void setData(void* valuep, const std::string& rhs);
|
||||
};
|
||||
|
||||
class VlWriteMem {
|
||||
bool m_hex; // Hex format
|
||||
int m_bits; // Bit width of values
|
||||
FILE* m_fp; // File handle for filename
|
||||
QData m_addr; // Next address to write
|
||||
public:
|
||||
VlWriteMem(bool hex, int bits, const std::string& filename, QData start, QData end);
|
||||
~VlWriteMem();
|
||||
bool isOpen() const { return m_fp != NULL; }
|
||||
bool isOpen() const { return m_fp != nullptr; }
|
||||
void print(QData addr, bool addrstamp, const void* valuep);
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
// Verilog array container
|
||||
// Similar to std::array<WData, N>, but:
|
||||
// 1. Doesn't require C++11
|
||||
// 2. Lighter weight, only methods needed by Verilator, to help compile time.
|
||||
// Similar to std::array<WData, N>, but lighter weight, only methods needed
|
||||
// by Verilator, to help compile time.
|
||||
//
|
||||
// This is only used when we need an upper-level container and so can't
|
||||
// simply use a C style array (which is just a pointer).
|
||||
|
||||
template <std::size_t T_Words> class VlWide {
|
||||
WData m_storage[T_Words];
|
||||
|
||||
public:
|
||||
// Default constructor/destructor/copy are fine
|
||||
// cppcheck-suppress uninitVar
|
||||
VlWide() {}
|
||||
~VlWide() {}
|
||||
const WData& at(size_t index) const { return m_storage[index]; }
|
||||
WData& at(size_t index) { return m_storage[index]; }
|
||||
WData* data() { return &m_storage[0]; }
|
||||
@@ -95,13 +99,11 @@ public:
|
||||
|
||||
// Convert a C array to std::array reference by pointer magic, without copy.
|
||||
// Data type (second argument) is so the function template can automatically generate.
|
||||
template <std::size_t T_Words>
|
||||
VlWide<T_Words>& VL_CVT_W_A(WDataInP inp, const VlWide<T_Words>&) {
|
||||
template <std::size_t T_Words> VlWide<T_Words>& VL_CVT_W_A(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());
|
||||
}
|
||||
|
||||
@@ -114,6 +116,7 @@ template <class T_Key, class T_Value> class VlAssocArray {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::map<T_Key, T_Value> Map;
|
||||
|
||||
public:
|
||||
typedef typename Map::const_iterator const_iterator;
|
||||
|
||||
@@ -142,21 +145,21 @@ public:
|
||||
int exists(const T_Key& index) const { return m_map.find(index) != m_map.end(); }
|
||||
// Return first element. Verilog: function int first(ref index);
|
||||
int first(T_Key& indexr) const {
|
||||
typename Map::const_iterator it = m_map.begin();
|
||||
const auto it = m_map.cbegin();
|
||||
if (it == m_map.end()) return 0;
|
||||
indexr = it->first;
|
||||
return 1;
|
||||
}
|
||||
// Return last element. Verilog: function int last(ref index)
|
||||
int last(T_Key& indexr) const {
|
||||
typename Map::const_reverse_iterator it = m_map.rbegin();
|
||||
const auto it = m_map.crbegin();
|
||||
if (it == m_map.rend()) return 0;
|
||||
indexr = it->first;
|
||||
return 1;
|
||||
}
|
||||
// Return next element. Verilog: function int next(ref index)
|
||||
int next(T_Key& indexr) const {
|
||||
typename Map::const_iterator it = m_map.find(indexr);
|
||||
auto it = m_map.find(indexr);
|
||||
if (VL_UNLIKELY(it == m_map.end())) return 0;
|
||||
++it;
|
||||
if (VL_UNLIKELY(it == m_map.end())) return 0;
|
||||
@@ -165,7 +168,7 @@ public:
|
||||
}
|
||||
// Return prev element. Verilog: function int prev(ref index)
|
||||
int prev(T_Key& indexr) const {
|
||||
typename Map::const_iterator it = m_map.find(indexr);
|
||||
auto it = m_map.find(indexr);
|
||||
if (VL_UNLIKELY(it == m_map.end())) return 0;
|
||||
if (VL_UNLIKELY(it == m_map.begin())) return 0;
|
||||
--it;
|
||||
@@ -176,7 +179,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(const T_Key& index) {
|
||||
typename Map::iterator it = m_map.find(index);
|
||||
const auto it = m_map.find(index);
|
||||
if (it == m_map.end()) {
|
||||
std::pair<typename Map::iterator, bool> pit
|
||||
= m_map.insert(std::make_pair(index, m_defaultValue));
|
||||
@@ -186,9 +189,12 @@ public:
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(const T_Key& index) const {
|
||||
typename Map::iterator it = m_map.find(index);
|
||||
if (it == m_map.end()) return m_defaultValue;
|
||||
else return it->second;
|
||||
const auto it = m_map.find(index);
|
||||
if (it == m_map.end()) {
|
||||
return m_defaultValue;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
// For save/restore
|
||||
const_iterator begin() const { return m_map.begin(); }
|
||||
@@ -198,8 +204,8 @@ public:
|
||||
std::string to_string() const {
|
||||
std::string out = "'{";
|
||||
std::string comma;
|
||||
for (typename Map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) {
|
||||
out += comma + VL_TO_STRING(it->first) + ":" + VL_TO_STRING(it->second);
|
||||
for (const auto& i : m_map) {
|
||||
out += comma + VL_TO_STRING(i.first) + ":" + VL_TO_STRING(i.second);
|
||||
comma = ", ";
|
||||
}
|
||||
// Default not printed - maybe random init data
|
||||
@@ -233,10 +239,9 @@ void VL_WRITEMEM_N(bool hex, int bits, const std::string& filename,
|
||||
const VlAssocArray<T_Key, T_Value>& obj, QData start, QData end) VL_MT_SAFE {
|
||||
VlWriteMem wmem(hex, bits, filename, start, end);
|
||||
if (VL_UNLIKELY(!wmem.isOpen())) return;
|
||||
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = obj.begin(); it != obj.end();
|
||||
++it) {
|
||||
QData addr = it->first;
|
||||
if (addr >= start && addr <= end) wmem.print(addr, true, &(it->second));
|
||||
for (const auto& i : obj) {
|
||||
QData addr = i.first;
|
||||
if (addr >= start && addr <= end) wmem.print(addr, true, &(i.second));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,6 +256,7 @@ template <class T_Value, size_t T_MaxSize = 0> class VlQueue {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::deque<T_Value> Deque;
|
||||
|
||||
public:
|
||||
typedef typename Deque::const_iterator const_iterator;
|
||||
|
||||
@@ -274,7 +280,9 @@ public:
|
||||
int size() const { return m_deque.size(); }
|
||||
// Clear array. Verilog: function void delete([input index])
|
||||
void clear() { m_deque.clear(); }
|
||||
void erase(size_t index) { if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index); }
|
||||
void erase(size_t index) {
|
||||
if (VL_LIKELY(index < m_deque.size())) m_deque.erase(index);
|
||||
}
|
||||
|
||||
// Dynamic array new[] becomes a renew()
|
||||
void renew(size_t size) {
|
||||
@@ -282,7 +290,7 @@ public:
|
||||
m_deque.resize(size, atDefault());
|
||||
}
|
||||
// Dynamic array new[]() becomes a renew_copy()
|
||||
void renew_copy(size_t size, const VlQueue<T_Value,T_MaxSize>& rhs) {
|
||||
void renew_copy(size_t size, const VlQueue<T_Value, T_MaxSize>& rhs) {
|
||||
if (size == 0) {
|
||||
clear();
|
||||
} else {
|
||||
@@ -303,12 +311,16 @@ public:
|
||||
// function value_t q.pop_front();
|
||||
T_Value pop_front() {
|
||||
if (m_deque.empty()) return m_defaultValue;
|
||||
T_Value v = m_deque.front(); m_deque.pop_front(); return v;
|
||||
T_Value v = m_deque.front();
|
||||
m_deque.pop_front();
|
||||
return v;
|
||||
}
|
||||
// function value_t q.pop_back();
|
||||
T_Value pop_back() {
|
||||
if (m_deque.empty()) return m_defaultValue;
|
||||
T_Value v = m_deque.back(); m_deque.pop_back(); return v;
|
||||
T_Value v = m_deque.back();
|
||||
m_deque.pop_back();
|
||||
return v;
|
||||
}
|
||||
|
||||
// Setting. Verilog: assoc[index] = v
|
||||
@@ -320,15 +332,19 @@ public:
|
||||
if (VL_UNLIKELY(index >= m_deque.size())) {
|
||||
s_throwAway = atDefault();
|
||||
return s_throwAway;
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
else return m_deque[index];
|
||||
}
|
||||
// Accessing. Verilog: v = assoc[index]
|
||||
const T_Value& at(size_t index) const {
|
||||
static T_Value s_throwAway;
|
||||
// Needs to work for dynamic arrays, so does not use T_MaxSize
|
||||
if (VL_UNLIKELY(index >= m_deque.size())) return atDefault();
|
||||
else return m_deque[index];
|
||||
if (VL_UNLIKELY(index >= m_deque.size())) {
|
||||
return atDefault();
|
||||
} else {
|
||||
return m_deque[index];
|
||||
}
|
||||
}
|
||||
// function void q.insert(index, value);
|
||||
void insert(size_t index, const T_Value& value) {
|
||||
@@ -344,44 +360,58 @@ public:
|
||||
std::string to_string() const {
|
||||
std::string out = "'{";
|
||||
std::string comma;
|
||||
for (typename Deque::const_iterator it = m_deque.begin(); it != m_deque.end(); ++it) {
|
||||
out += comma + VL_TO_STRING(*it);
|
||||
for (const auto& i : m_deque) {
|
||||
out += comma + VL_TO_STRING(i);
|
||||
comma = ", ";
|
||||
}
|
||||
return out + "} ";
|
||||
}
|
||||
};
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
//===================================================================
|
||||
// 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 <class T> // T typically of type VlClassRef<x>
|
||||
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
|
||||
if (VL_UNLIKELY(!t)) Verilated::nullPointerError(filename, linenum);
|
||||
return t;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Conversion functions
|
||||
|
||||
extern std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp) VL_MT_SAFE;
|
||||
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE {
|
||||
WData lw[VL_WQ_WORDS_E]; VL_SET_WQ(lw, lhs);
|
||||
WData lw[VL_WQ_WORDS_E];
|
||||
VL_SET_WQ(lw, lhs);
|
||||
return VL_CVT_PACK_STR_NW(VL_WQ_WORDS_E, lw);
|
||||
}
|
||||
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE {
|
||||
return lhs;
|
||||
}
|
||||
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE { return lhs; }
|
||||
inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE {
|
||||
WData lw[VL_WQ_WORDS_E]; VL_SET_WI(lw, lhs);
|
||||
WData lw[VL_WQ_WORDS_E];
|
||||
VL_SET_WI(lw, lhs);
|
||||
return VL_CVT_PACK_STR_NW(1, lw);
|
||||
}
|
||||
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) VL_PURE {
|
||||
return lhs + rhs;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNQ(int,int,int, const std::string& lhs, IData rep) VL_PURE {
|
||||
std::string out; out.reserve(lhs.length() * rep);
|
||||
for (unsigned times=0; times<rep; ++times) out += lhs;
|
||||
inline std::string VL_REPLICATEN_NNQ(int, int, int, const std::string& lhs, IData rep) VL_PURE {
|
||||
std::string out;
|
||||
out.reserve(lhs.length() * rep);
|
||||
for (unsigned times = 0; times < rep; ++times) out += lhs;
|
||||
return out;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNI(int obits,int lbits,int rbits,
|
||||
const std::string& lhs, IData rep) VL_PURE {
|
||||
inline std::string VL_REPLICATEN_NNI(int obits, int lbits, int rbits, const std::string& lhs,
|
||||
IData rep) VL_PURE {
|
||||
return VL_REPLICATEN_NNQ(obits, lbits, rbits, lhs, rep);
|
||||
}
|
||||
|
||||
@@ -389,18 +419,21 @@ inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
|
||||
extern std::string VL_TOLOWER_NN(const std::string& ld);
|
||||
extern std::string VL_TOUPPER_NN(const std::string& ld);
|
||||
|
||||
extern IData VL_FOPEN_NI(const std::string& filename, IData mode) VL_MT_SAFE;
|
||||
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
|
||||
extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE;
|
||||
extern IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE;
|
||||
extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb,
|
||||
const std::string& filename, void* memp, QData start,
|
||||
QData end) VL_MT_SAFE;
|
||||
extern void VL_WRITEMEM_N(bool hex, int bits, QData depth, int array_lsb,
|
||||
const std::string& filename, const void* memp, QData start,
|
||||
QData end) VL_MT_SAFE;
|
||||
extern IData VL_SSCANF_INX(int lbits, const std::string& ld,
|
||||
const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits_ignored, std::string& output,
|
||||
const char* formatp, ...) VL_MT_SAFE;
|
||||
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp,
|
||||
...) VL_MT_SAFE;
|
||||
extern std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE;
|
||||
extern void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix,
|
||||
int width) VL_MT_SAFE;
|
||||
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_MT_SAFE;
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, CData& rdr) VL_MT_SAFE {
|
||||
WData rwp[2]; // WData must always be at least 2
|
||||
|
||||
+293
-120
@@ -19,6 +19,7 @@
|
||||
#ifndef _VERILATED_IMP_H_
|
||||
#define _VERILATED_IMP_H_ 1 ///< Header Guard
|
||||
|
||||
// clang-format off
|
||||
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_) && !defined(_VERILATED_VPI_CPP_)
|
||||
# error "verilated_imp.h only to be included by verilated*.cpp internals"
|
||||
#endif
|
||||
@@ -31,10 +32,12 @@
|
||||
#include <deque>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <numeric>
|
||||
#ifdef VL_THREADED
|
||||
# include <functional>
|
||||
# include <queue>
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
class VerilatedScope;
|
||||
|
||||
@@ -47,9 +50,11 @@ class VerilatedMsg {
|
||||
public:
|
||||
// TYPES
|
||||
struct Cmp {
|
||||
bool operator() (const VerilatedMsg& a, const VerilatedMsg& b) const {
|
||||
return a.mtaskId() < b.mtaskId(); }
|
||||
bool operator()(const VerilatedMsg& a, const VerilatedMsg& b) const {
|
||||
return a.mtaskId() < b.mtaskId();
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
vluint32_t m_mtaskId; ///< MTask that did enqueue
|
||||
@@ -57,8 +62,8 @@ private:
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedMsg(const std::function<void()>& cb)
|
||||
: m_mtaskId(Verilated::mtaskId())
|
||||
, m_cb(cb) {}
|
||||
: m_mtaskId{Verilated::mtaskId()}
|
||||
, m_cb{cb} {}
|
||||
~VerilatedMsg() {}
|
||||
// METHODS
|
||||
vluint32_t mtaskId() const { return m_mtaskId; }
|
||||
@@ -79,18 +84,19 @@ class VerilatedEvalMsgQueue {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedEvalMsgQueue()
|
||||
: m_depth(0) {
|
||||
: m_depth{0} {
|
||||
assert(atomic_is_lock_free(&m_depth));
|
||||
}
|
||||
~VerilatedEvalMsgQueue() {}
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedEvalMsgQueue);
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
//// Add message to queue (called by producer)
|
||||
void post(const VerilatedMsg& msg) VL_EXCLUDES(m_mutex) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
const VerilatedLockGuard lock(m_mutex);
|
||||
m_queue.insert(msg); // Pass by value to copy the message into queue
|
||||
++m_depth;
|
||||
}
|
||||
@@ -106,7 +112,7 @@ public:
|
||||
// Unfortunately to release the lock we need to copy the message
|
||||
// (Or have the message be a pointer, but then new/delete cost on each message)
|
||||
// We assume messages are small, so copy
|
||||
auto it = m_queue.begin();
|
||||
const auto it = m_queue.begin();
|
||||
const VerilatedMsg msg = *(it);
|
||||
m_queue.erase(it);
|
||||
m_mutex.unlock();
|
||||
@@ -122,6 +128,7 @@ public:
|
||||
/// Each thread has a local queue to build up messages until the end of the eval() call
|
||||
class VerilatedThreadMsgQueue {
|
||||
std::queue<VerilatedMsg> m_queue;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedThreadMsgQueue() {}
|
||||
@@ -129,6 +136,7 @@ public:
|
||||
// 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.
|
||||
}
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
|
||||
// METHODS
|
||||
@@ -136,6 +144,7 @@ private:
|
||||
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
|
||||
return t_s;
|
||||
}
|
||||
|
||||
public:
|
||||
/// Add message to queue, called by producer
|
||||
static void post(const VerilatedMsg& msg) VL_MT_SAFE {
|
||||
@@ -160,11 +169,31 @@ public:
|
||||
};
|
||||
#endif // VL_THREADED
|
||||
|
||||
// FILE* list constructed from a file-descriptor
|
||||
class VerilatedFpList {
|
||||
FILE* m_fp[31];
|
||||
std::size_t m_sz = 0;
|
||||
|
||||
public:
|
||||
typedef FILE* const* const_iterator;
|
||||
explicit VerilatedFpList() {}
|
||||
const_iterator begin() const { return m_fp; }
|
||||
const_iterator end() const { return m_fp + m_sz; }
|
||||
std::size_t size() const { return m_sz; }
|
||||
std::size_t capacity() const { return 31; }
|
||||
void push_back(FILE* fd) {
|
||||
if (VL_LIKELY(size() < capacity())) m_fp[m_sz++] = fd;
|
||||
}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
// VerilatedImp
|
||||
|
||||
class VerilatedImp {
|
||||
class VerilatedImpData {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
protected:
|
||||
friend class Verilated;
|
||||
friend class VerilatedImp;
|
||||
|
||||
// TYPES
|
||||
typedef std::vector<std::string> ArgVec;
|
||||
@@ -172,46 +201,88 @@ class VerilatedImp {
|
||||
typedef std::map<const char*, int, VerilatedCStrCmp> ExportNameMap;
|
||||
|
||||
// MEMBERS
|
||||
static VerilatedImp s_s; ///< Static Singleton; One and only static this
|
||||
|
||||
// Nothing here is save-restored; users expected to re-register appropriately
|
||||
struct Serialized { // All these members serialized/deserialized
|
||||
int m_timeFormatUnits = UNITS_NONE; // $timeformat units
|
||||
int m_timeFormatPrecision = 0; // $timeformat number of decimal places
|
||||
int m_timeFormatWidth = 20; // $timeformat character width
|
||||
enum { UNITS_NONE = 99 }; // Default based on precision
|
||||
Serialized() {}
|
||||
~Serialized() {}
|
||||
} m_ser;
|
||||
|
||||
VerilatedMutex m_argMutex; ///< Protect m_argVec, m_argVecLoaded
|
||||
ArgVec m_argVec VL_GUARDED_BY(m_argMutex); ///< Argument list (NOT save-restored, may want different results)
|
||||
bool m_argVecLoaded VL_GUARDED_BY(m_argMutex); ///< Ever loaded argument list
|
||||
VerilatedMutex m_sergMutex; ///< Protect m_ser
|
||||
struct SerializedG { // All these members serialized/deserialized and guarded
|
||||
std::string m_timeFormatSuffix; // $timeformat printf format
|
||||
} m_serg VL_GUARDED_BY(m_sergMutex);
|
||||
|
||||
VerilatedMutex m_userMapMutex; ///< Protect m_userMap
|
||||
UserMap m_userMap VL_GUARDED_BY(m_userMapMutex); ///< Map of <(scope,userkey), userData>
|
||||
// Nothing below here is save-restored; users expected to re-register appropriately
|
||||
|
||||
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
|
||||
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex); ///< Map of <scope_name, scope pointer>
|
||||
VerilatedMutex m_argMutex; ///< Protect m_argVec, m_argVecLoaded
|
||||
/// Argument list (NOT save-restored, may want different results)
|
||||
ArgVec m_argVec VL_GUARDED_BY(m_argMutex);
|
||||
bool m_argVecLoaded VL_GUARDED_BY(m_argMutex); ///< Ever loaded argument list
|
||||
|
||||
VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap
|
||||
VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex); ///< Map the represents scope hierarchy
|
||||
VerilatedMutex m_userMapMutex; ///< Protect m_userMap
|
||||
UserMap m_userMap VL_GUARDED_BY(m_userMapMutex); ///< Map of <(scope,userkey), userData>
|
||||
|
||||
VerilatedMutex m_nameMutex; ///< Protect m_nameMap
|
||||
/// Map of <scope_name, scope pointer>
|
||||
VerilatedScopeNameMap m_nameMap VL_GUARDED_BY(m_nameMutex);
|
||||
|
||||
VerilatedMutex m_hierMapMutex; ///< Protect m_hierMap
|
||||
/// Map the represents scope hierarchy
|
||||
VerilatedHierarchyMap m_hierMap VL_GUARDED_BY(m_hierMapMutex);
|
||||
|
||||
// Slow - somewhat static:
|
||||
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
|
||||
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex); ///< Map of <export_func_proto, func number>
|
||||
int m_exportNext VL_GUARDED_BY(m_exportMutex); ///< Next export funcnum
|
||||
VerilatedMutex m_exportMutex; ///< Protect m_nameMap
|
||||
/// Map of <export_func_proto, func number>
|
||||
ExportNameMap m_exportMap VL_GUARDED_BY(m_exportMutex);
|
||||
int m_exportNext VL_GUARDED_BY(m_exportMutex); ///< Next export funcnum
|
||||
|
||||
// File I/O
|
||||
VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree
|
||||
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
|
||||
std::deque<IData> m_fdFree VL_GUARDED_BY(m_fdMutex); ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||
VerilatedMutex m_fdMutex; ///< Protect m_fdps, m_fdFree
|
||||
std::vector<FILE*> m_fdps VL_GUARDED_BY(m_fdMutex); ///< File descriptors
|
||||
/// List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||
std::vector<IData> m_fdFree VL_GUARDED_BY(m_fdMutex);
|
||||
// List of free descriptors in the MCT region [4, 32)
|
||||
std::vector<IData> m_fdFreeMct VL_GUARDED_BY(m_fdMutex);
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedImpData()
|
||||
: m_argVecLoaded{false}
|
||||
, m_exportNext{0} {
|
||||
|
||||
m_fdps.resize(31);
|
||||
std::fill(m_fdps.begin(), m_fdps.end(), (FILE*)0);
|
||||
m_fdFreeMct.resize(30);
|
||||
for (std::size_t i = 0, id = 1; i < m_fdFreeMct.size(); ++i, ++id) { m_fdFreeMct[i] = id; }
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedImp {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
protected:
|
||||
friend class Verilated;
|
||||
|
||||
// MEMBERS
|
||||
union VerilatedImpU { ///< Enclose in an union to call ctor/dtor manually
|
||||
VerilatedImpData v;
|
||||
VerilatedImpU() {}
|
||||
~VerilatedImpU() {}
|
||||
};
|
||||
static VerilatedImpU s_s; ///< Static Singleton; One and only static this
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// CONSTRUCTORS
|
||||
VerilatedImp()
|
||||
: m_argVecLoaded(false)
|
||||
, m_exportNext(0) {
|
||||
m_fdps.resize(3);
|
||||
m_fdps[0] = stdin;
|
||||
m_fdps[1] = stdout;
|
||||
m_fdps[2] = stderr;
|
||||
}
|
||||
VerilatedImp() {}
|
||||
~VerilatedImp() {}
|
||||
static void setup();
|
||||
static void teardown();
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VerilatedImp);
|
||||
|
||||
public:
|
||||
// METHODS - debug
|
||||
static void internalsDump() VL_MT_SAFE;
|
||||
@@ -219,30 +290,31 @@ public:
|
||||
|
||||
// METHODS - arguments
|
||||
public:
|
||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.m_argMutex);
|
||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.m_argMutex) {
|
||||
VerilatedLockGuard lock(s_s.m_argMutex);
|
||||
static void commandArgs(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex);
|
||||
static void commandArgsAdd(int argc, const char** argv) VL_EXCLUDES(s_s.v.m_argMutex);
|
||||
static std::string argPlusMatch(const char* prefixp) VL_EXCLUDES(s_s.v.m_argMutex) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_argMutex);
|
||||
// Note prefixp does not include the leading "+"
|
||||
size_t len = strlen(prefixp);
|
||||
if (VL_UNLIKELY(!s_s.m_argVecLoaded)) {
|
||||
s_s.m_argVecLoaded = true; // Complain only once
|
||||
if (VL_UNLIKELY(!s_s.v.m_argVecLoaded)) {
|
||||
s_s.v.m_argVecLoaded = true; // Complain only once
|
||||
VL_FATAL_MT("unknown", 0, "",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::const_iterator it = s_s.m_argVec.begin(); it != s_s.m_argVec.end(); ++it) {
|
||||
if ((*it)[0] == '+') {
|
||||
if (0 == strncmp(prefixp, it->c_str() + 1, len)) return *it;
|
||||
for (const auto& i : s_s.v.m_argVec) {
|
||||
if (i[0] == '+') {
|
||||
if (0 == strncmp(prefixp, i.c_str() + 1, len)) return i;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
private:
|
||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.m_argMutex);
|
||||
static void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(s_s.v.m_argMutex);
|
||||
static void commandArgVl(const std::string& arg);
|
||||
static bool commandArgVlValue(const std::string& arg,
|
||||
const std::string& prefix, std::string& valuer);
|
||||
static bool commandArgVlValue(const std::string& arg, const std::string& prefix,
|
||||
std::string& valuer);
|
||||
|
||||
public:
|
||||
// METHODS - user scope tracking
|
||||
@@ -250,38 +322,45 @@ public:
|
||||
// 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.
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::iterator it = s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (it != s_s.m_userMap.end()) it->second = userData;
|
||||
// When we support VL_THREADs, we need a lock around this insert, as it's runtime
|
||||
else s_s.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
|
||||
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
|
||||
const auto it = s_s.v.m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (it != s_s.v.m_userMap.end()) {
|
||||
it->second = userData;
|
||||
} else {
|
||||
s_s.v.m_userMap.insert(it, std::make_pair(std::make_pair(scopep, userKey), userData));
|
||||
}
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
UserMap::const_iterator it=s_s.m_userMap.find(std::make_pair(scopep, userKey));
|
||||
if (VL_LIKELY(it != s_s.m_userMap.end())) return it->second;
|
||||
else return NULL;
|
||||
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
|
||||
const auto& it = vlstd::as_const(s_s.v.m_userMap).find(std::make_pair(scopep, userKey));
|
||||
if (VL_UNLIKELY(it == s_s.v.m_userMap.end())) return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
|
||||
private:
|
||||
/// 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 simply iterate.
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex);
|
||||
for (UserMap::iterator it = s_s.m_userMap.begin(); it != s_s.m_userMap.end();) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_userMapMutex);
|
||||
for (auto it = s_s.v.m_userMap.begin(); it != s_s.v.m_userMap.end();) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
s_s.v.m_userMap.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void userDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_userMapMutex); // Avoid it changing in middle of dump
|
||||
const VerilatedLockGuard lock(
|
||||
s_s.v.m_userMapMutex); // Avoid it changing in middle of dump
|
||||
bool first = true;
|
||||
for (UserMap::const_iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" userDump:\n"); first=false; }
|
||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n",
|
||||
it->first.first, it->first.second, it->second);
|
||||
for (const auto& i : s_s.v.m_userMap) {
|
||||
if (first) {
|
||||
VL_PRINTF_MT(" userDump:\n");
|
||||
first = false;
|
||||
}
|
||||
VL_PRINTF_MT(" DPI_USER_DATA scope %p key %p: %p\n", i.first.first, i.first.second,
|
||||
i.second);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -289,51 +368,50 @@ public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
static void scopeInsert(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at construction
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.m_nameMap.end()) {
|
||||
s_s.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
|
||||
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
|
||||
const auto it = s_s.v.m_nameMap.find(scopep->name());
|
||||
if (it == s_s.v.m_nameMap.end()) {
|
||||
s_s.v.m_nameMap.insert(it, std::make_pair(scopep->name(), scopep));
|
||||
}
|
||||
}
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
|
||||
// If too slow, can assume this is only VL_MT_SAFE_POSINIT
|
||||
VerilatedScopeNameMap::const_iterator it=s_s.m_nameMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||
else return NULL;
|
||||
const auto& it = s_s.v.m_nameMap.find(namep);
|
||||
if (VL_UNLIKELY(it == s_s.v.m_nameMap.end())) return nullptr;
|
||||
return it->second;
|
||||
}
|
||||
static void scopeErase(const VerilatedScope* scopep) VL_MT_SAFE {
|
||||
// Slow ok - called once/scope at destruction
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
|
||||
userEraseScope(scopep);
|
||||
VerilatedScopeNameMap::iterator it = s_s.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.m_nameMap.end()) s_s.m_nameMap.erase(it);
|
||||
const auto it = s_s.v.m_nameMap.find(scopep->name());
|
||||
if (it != s_s.v.m_nameMap.end()) s_s.v.m_nameMap.erase(it);
|
||||
}
|
||||
static void scopesDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_nameMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_nameMutex);
|
||||
VL_PRINTF_MT(" scopesDump:\n");
|
||||
for (VerilatedScopeNameMap::const_iterator it = s_s.m_nameMap.begin();
|
||||
it != s_s.m_nameMap.end(); ++it) {
|
||||
const VerilatedScope* scopep = it->second;
|
||||
for (const auto& i : s_s.v.m_nameMap) {
|
||||
const VerilatedScope* scopep = i.second;
|
||||
scopep->scopeDump();
|
||||
}
|
||||
VL_PRINTF_MT("\n");
|
||||
}
|
||||
static const VerilatedScopeNameMap* scopeNameMap() VL_MT_SAFE_POSTINIT {
|
||||
// Thread save only assuming this is called only after model construction completed
|
||||
return &s_s.m_nameMap;
|
||||
return &s_s.v.m_nameMap;
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - hierarchy
|
||||
static void hierarchyAdd(const VerilatedScope* fromp, const VerilatedScope* top) VL_MT_SAFE {
|
||||
// Slow ok - called at construction for VPI accessible elements
|
||||
VerilatedLockGuard lock(s_s.m_hierMapMutex);
|
||||
s_s.m_hierMap[fromp].push_back(top);
|
||||
const VerilatedLockGuard lock(s_s.v.m_hierMapMutex);
|
||||
s_s.v.m_hierMap[fromp].push_back(top);
|
||||
}
|
||||
static const VerilatedHierarchyMap* hierarchyMap() VL_MT_SAFE_POSTINIT {
|
||||
// Thread save only assuming this is called only after model construction completed
|
||||
return &s_s.m_hierMap;
|
||||
return &s_s.v.m_hierMap;
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
@@ -347,74 +425,169 @@ public: // But only for verilated*.cpp
|
||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||
static int exportInsert(const char* namep) VL_MT_SAFE {
|
||||
// Slow ok - called once/function at creation
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::iterator it = s_s.m_exportMap.find(namep);
|
||||
if (it == s_s.m_exportMap.end()) {
|
||||
s_s.m_exportMap.insert(it, std::make_pair(namep, s_s.m_exportNext++));
|
||||
return s_s.m_exportNext++;
|
||||
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
|
||||
const auto it = s_s.v.m_exportMap.find(namep);
|
||||
if (it == s_s.v.m_exportMap.end()) {
|
||||
s_s.v.m_exportMap.insert(it, std::make_pair(namep, s_s.v.m_exportNext++));
|
||||
return s_s.v.m_exportNext++;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
static int exportFind(const char* namep) VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
ExportNameMap::const_iterator it = s_s.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_exportMap.end())) return it->second;
|
||||
std::string msg = (std::string("%Error: Testbench C called ")+namep
|
||||
+" but no such DPI export function name exists in ANY model");
|
||||
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
|
||||
const auto& it = s_s.v.m_exportMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.v.m_exportMap.end())) return it->second;
|
||||
std::string msg = (std::string("%Error: Testbench C called ") + namep
|
||||
+ " but no such DPI export function name exists in ANY model");
|
||||
VL_FATAL_MT("unknown", 0, "", msg.c_str());
|
||||
return -1;
|
||||
}
|
||||
static const char* exportName(int funcnum) VL_MT_SAFE {
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
for (ExportNameMap::const_iterator it = s_s.m_exportMap.begin();
|
||||
it != s_s.m_exportMap.end(); ++it) {
|
||||
if (it->second == funcnum) return it->first;
|
||||
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
|
||||
for (const auto& i : s_s.v.m_exportMap) {
|
||||
if (i.second == funcnum) return i.first;
|
||||
}
|
||||
return "*UNKNOWN*";
|
||||
}
|
||||
static void exportsDump() VL_MT_SAFE {
|
||||
VerilatedLockGuard lock(s_s.m_exportMutex);
|
||||
const VerilatedLockGuard lock(s_s.v.m_exportMutex);
|
||||
bool first = true;
|
||||
for (ExportNameMap::const_iterator it=s_s.m_exportMap.begin();
|
||||
it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF_MT(" exportDump:\n"); first=false; }
|
||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||
for (const auto& i : s_s.v.m_exportMap) {
|
||||
if (first) {
|
||||
VL_PRINTF_MT(" exportDump:\n");
|
||||
first = false;
|
||||
}
|
||||
VL_PRINTF_MT(" DPI_EXPORT_NAME %05d: %s\n", i.second, i.first);
|
||||
}
|
||||
}
|
||||
// We don't free up m_exportMap until the end, because we can't be sure
|
||||
// what other models are using the assigned funcnum's.
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - timeformat
|
||||
static std::string timeFormatSuffix() VL_MT_SAFE;
|
||||
static void timeFormatSuffix(const std::string& value) VL_MT_SAFE;
|
||||
static int timeFormatUnits() VL_MT_SAFE {
|
||||
if (s_s.v.m_ser.m_timeFormatUnits == VerilatedImpData::Serialized::UNITS_NONE) {
|
||||
return Verilated::timeprecision();
|
||||
}
|
||||
return s_s.v.m_ser.m_timeFormatUnits;
|
||||
}
|
||||
static int timeFormatPrecision() VL_MT_SAFE { return s_s.v.m_ser.m_timeFormatPrecision; }
|
||||
static int timeFormatWidth() VL_MT_SAFE { return s_s.v.m_ser.m_timeFormatWidth; }
|
||||
static void timeFormatUnits(int value) VL_MT_SAFE;
|
||||
static void timeFormatPrecision(int value) VL_MT_SAFE;
|
||||
static void timeFormatWidth(int value) VL_MT_SAFE;
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - file IO
|
||||
static IData fdNew(FILE* fp) VL_MT_SAFE {
|
||||
static IData fdNewMcd(const char* filenamep) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
if (s_s.v.m_fdFreeMct.empty()) return 0;
|
||||
IData idx = s_s.v.m_fdFreeMct.back();
|
||||
s_s.v.m_fdFreeMct.pop_back();
|
||||
s_s.v.m_fdps[idx] = fopen(filenamep, "w");
|
||||
if (VL_UNLIKELY(!s_s.v.m_fdps[idx])) return 0;
|
||||
return (1 << idx);
|
||||
}
|
||||
static IData fdNew(const char* filenamep, const char* modep) VL_MT_SAFE {
|
||||
FILE* fp = fopen(filenamep, modep);
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
// Bit 31 indicates it's a descriptor not a MCD
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (s_s.m_fdFree.empty()) {
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
if (s_s.v.m_fdFree.empty()) {
|
||||
// Need to create more space in m_fdps and m_fdFree
|
||||
size_t start = s_s.m_fdps.size();
|
||||
s_s.m_fdps.resize(start*2);
|
||||
for (size_t i=start; i<start*2; ++i) s_s.m_fdFree.push_back(static_cast<IData>(i));
|
||||
const std::size_t start = std::max<std::size_t>(31UL + 1UL + 3UL, s_s.v.m_fdps.size());
|
||||
const std::size_t excess = 10;
|
||||
s_s.v.m_fdps.resize(start + excess);
|
||||
std::fill(s_s.v.m_fdps.begin() + start, s_s.v.m_fdps.end(), (FILE*)0);
|
||||
s_s.v.m_fdFree.resize(excess);
|
||||
for (std::size_t i = 0, id = start; i < s_s.v.m_fdFree.size(); ++i, ++id) {
|
||||
s_s.v.m_fdFree[i] = id;
|
||||
}
|
||||
}
|
||||
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
|
||||
s_s.m_fdps[idx] = fp;
|
||||
return (idx | (1UL<<31)); // bit 31 indicates not MCD
|
||||
IData idx = s_s.v.m_fdFree.back();
|
||||
s_s.v.m_fdFree.pop_back();
|
||||
s_s.v.m_fdps[idx] = fp;
|
||||
return (idx | (1UL << 31)); // bit 31 indicates not MCD
|
||||
}
|
||||
static void fdDelete(IData fdi) VL_MT_SAFE {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex);
|
||||
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
|
||||
s_s.m_fdps[idx] = NULL;
|
||||
s_s.m_fdFree.push_back(idx);
|
||||
static void fdFlush(IData fdi) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
for (const auto& i : fdlist) fflush(i);
|
||||
}
|
||||
static IData fdSeek(IData fdi, IData offset, IData origin) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
|
||||
return static_cast<IData>(
|
||||
fseek(*fdlist.begin(), static_cast<long>(offset), static_cast<int>(origin)));
|
||||
}
|
||||
static IData fdTell(IData fdi) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
if (VL_UNLIKELY(fdlist.size() != 1)) return 0;
|
||||
return static_cast<IData>(ftell(*fdlist.begin()));
|
||||
}
|
||||
static void fdWrite(IData fdi, const std::string& output) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
for (const auto& i : fdlist) {
|
||||
if (VL_UNLIKELY(!i)) continue;
|
||||
(void)fwrite(output.c_str(), 1, output.size(), i);
|
||||
}
|
||||
}
|
||||
static void fdClose(IData fdi) VL_MT_SAFE {
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
if ((fdi & (1 << 31)) != 0) {
|
||||
// Non-MCD case
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
if (VL_UNLIKELY(idx >= s_s.v.m_fdps.size())) return;
|
||||
if (VL_UNLIKELY(!s_s.v.m_fdps[idx])) return; // Already free
|
||||
fclose(s_s.v.m_fdps[idx]);
|
||||
s_s.v.m_fdps[idx] = (FILE*)0;
|
||||
s_s.v.m_fdFree.push_back(idx);
|
||||
} else {
|
||||
// MCD case
|
||||
for (int i = 0; (fdi != 0) && (i < 31); i++, fdi >>= 1) {
|
||||
if (fdi & VL_MASK_I(1)) {
|
||||
fclose(s_s.v.m_fdps[i]);
|
||||
s_s.v.m_fdps[i] = nullptr;
|
||||
s_s.v.m_fdFreeMct.push_back(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
static inline FILE* fdToFp(IData fdi) VL_MT_SAFE {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
VerilatedLockGuard lock(s_s.m_fdMutex); // This might get slow, if it does we can cache it
|
||||
if (VL_UNLIKELY(!(fdi & (VL_ULL(1) << 31)) || idx >= s_s.m_fdps.size())) return NULL;
|
||||
return s_s.m_fdps[idx];
|
||||
const VerilatedLockGuard lock(s_s.v.m_fdMutex);
|
||||
const VerilatedFpList fdlist = fdToFpList(fdi);
|
||||
if (VL_UNLIKELY(fdlist.size() != 1)) return nullptr;
|
||||
return *fdlist.begin();
|
||||
}
|
||||
|
||||
private:
|
||||
static inline VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(s_s.v.m_fdMutex) {
|
||||
VerilatedFpList fp;
|
||||
if ((fdi & (1 << 31)) != 0) {
|
||||
// Non-MCD case
|
||||
const IData idx = fdi & VL_MASK_I(31);
|
||||
switch (idx) {
|
||||
case 0: fp.push_back(stdin); break;
|
||||
case 1: fp.push_back(stdout); break;
|
||||
case 2: fp.push_back(stderr); break;
|
||||
default:
|
||||
if (VL_LIKELY(idx < s_s.v.m_fdps.size())) fp.push_back(s_s.v.m_fdps[idx]);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// MCD Case
|
||||
for (int i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) {
|
||||
if (fdi & VL_MASK_I(1)) fp.push_back(s_s.v.m_fdps[i]);
|
||||
}
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Common include for target specific intrinsics.
|
||||
///
|
||||
/// Code using machine specific intrinsics for optimization should
|
||||
/// include this header rather than directly including he target
|
||||
/// specific headers. We provide macros to check for availability
|
||||
/// of instruction sets, and a common mechanism to disable them.
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _VERILATED_INTRINSICS_H_
|
||||
#define _VERILATED_INTRINSICS_H_ 1 ///< Header Guard
|
||||
|
||||
// clang-format off
|
||||
|
||||
// Use VL_DISABLE_INTRINSICS to disable all intrinsics based optimization
|
||||
#if !defined(VL_DISABLE_INTRINSICS) && !defined(VL_PORTABLE_ONLY)
|
||||
# if defined(__SSE2__) && !defined(VL_DISABLE_SSE2)
|
||||
# define VL_HAVE_SSE2 1
|
||||
# include <emmintrin.h>
|
||||
# endif
|
||||
# if defined(__AVX2__) && defined(VL_HAVE_SSE2) && !defined(VL_DISABLE_AVX2)
|
||||
# define VL_HAVE_AVX2 1
|
||||
# include <immintrin.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
#endif // Guard
|
||||
+50
-40
@@ -23,6 +23,7 @@
|
||||
#include <cerrno>
|
||||
#include <fcntl.h>
|
||||
|
||||
// clang-format off
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
# include <io.h>
|
||||
#else
|
||||
@@ -38,34 +39,36 @@
|
||||
#ifndef O_CLOEXEC
|
||||
# define O_CLOEXEC 0
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// CONSTANTS
|
||||
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file
|
||||
static const char* const VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
||||
/// Value of first bytes of each file (must be multiple of 8 bytes)
|
||||
static const char* const VLTSAVE_HEADER_STR = "verilatorsave01\n";
|
||||
/// Value of last bytes of each file (must be multiple of 8 bytes)
|
||||
static const char* const VLTSAVE_TRAILER_STR = "vltsaved";
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Searalization
|
||||
|
||||
bool VerilatedDeserialize::readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
bool VerilatedDeserialize::readDiffers(const void* __restrict datap,
|
||||
size_t size) VL_MT_UNSAFE_ONE {
|
||||
bufferCheck();
|
||||
const vluint8_t* __restrict dp = static_cast<const vluint8_t* __restrict>(datap);
|
||||
vluint8_t miss = 0;
|
||||
while (size--) {
|
||||
miss |= (*dp++ ^ *m_cp++);
|
||||
}
|
||||
return (miss!=0);
|
||||
while (size--) miss |= (*dp++ ^ *m_cp++);
|
||||
return (miss != 0);
|
||||
}
|
||||
|
||||
VerilatedDeserialize& VerilatedDeserialize::readAssert(const void* __restrict datap,
|
||||
size_t size) VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(readDiffers(datap, size))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = "Can't deserialize save-restore file as was made from different model:"
|
||||
+filename();
|
||||
std::string msg = "Can't deserialize save-restore file as was made from different model: "
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
@@ -77,19 +80,23 @@ void VerilatedSerialize::header() VL_MT_UNSAFE_ONE {
|
||||
|
||||
// Verilated doesn't do it itself, as if we're not using save/restore
|
||||
// it doesn't need to compile this stuff in
|
||||
os.write(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||
os.write(Verilated::serialized1Ptr(), Verilated::serialized1Size());
|
||||
os.write(Verilated::serialized2Ptr(), Verilated::serialized2Size());
|
||||
}
|
||||
|
||||
void VerilatedDeserialize::header() VL_MT_UNSAFE_ONE {
|
||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = std::string("Can't deserialize; file has wrong header signature: ")
|
||||
+filename();
|
||||
std::string msg
|
||||
= std::string(
|
||||
"Can't deserialize; file has wrong header signature, or file not found: ")
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||
os.read(Verilated::serialized1Ptr(), Verilated::serialized1Size());
|
||||
os.read(Verilated::serialized2Ptr(), Verilated::serialized2Size());
|
||||
}
|
||||
|
||||
void VerilatedSerialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
@@ -103,9 +110,9 @@ void VerilatedDeserialize::trailer() VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = std::string("Can't deserialize; file has wrong end-of-file signature: ")
|
||||
+filename();
|
||||
+ filename();
|
||||
VL_FATAL_MT(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
// Die before we close() as close would infinite loop
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,13 +126,13 @@ void VerilatedSave::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
if (isOpen()) return;
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- save: opening save file %s\n", filenamep););
|
||||
|
||||
if (filenamep[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
if (VL_UNCOVERABLE(filenamep[0] == '|')) {
|
||||
assert(0); // LCOV_EXCL_LINE // Not supported yet.
|
||||
} else {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
m_fd = ::open(filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK|O_CLOEXEC
|
||||
, 0666);
|
||||
if (m_fd<0) {
|
||||
m_fd = ::open(filenamep,
|
||||
O_CREAT | O_WRONLY | O_TRUNC | O_LARGEFILE | O_NONBLOCK | O_CLOEXEC, 0666);
|
||||
if (VL_UNLIKELY(m_fd < 0)) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
@@ -142,13 +149,12 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
|
||||
if (isOpen()) return;
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("- restore: opening restore file %s\n", filenamep););
|
||||
|
||||
if (filenamep[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
if (VL_UNCOVERABLE(filenamep[0] == '|')) {
|
||||
assert(0); // LCOV_EXCL_LINE // Not supported yet.
|
||||
} else {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
m_fd = ::open(filenamep, O_CREAT|O_RDONLY|O_LARGEFILE|O_CLOEXEC
|
||||
, 0666);
|
||||
if (m_fd<0) {
|
||||
m_fd = ::open(filenamep, O_CREAT | O_RDONLY | O_LARGEFILE | O_CLOEXEC, 0666);
|
||||
if (VL_UNLIKELY(m_fd < 0)) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
@@ -186,18 +192,20 @@ void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
|
||||
vluint8_t* wp = m_bufp;
|
||||
while (true) {
|
||||
ssize_t remaining = (m_cp - wp);
|
||||
if (remaining==0) break;
|
||||
if (remaining == 0) break;
|
||||
errno = 0;
|
||||
ssize_t got = ::write(m_fd, wp, remaining);
|
||||
if (got>0) {
|
||||
if (got > 0) {
|
||||
wp += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
} else if (VL_UNCOVERABLE(got < 0)) {
|
||||
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
|
||||
// LCOV_EXCL_START
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
close();
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,29 +217,31 @@ void VerilatedRestore::fill() VL_MT_UNSAFE_ONE {
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
// Move remaining characters down to start of buffer. (No memcpy, overlaps allowed)
|
||||
vluint8_t* rp = m_bufp;
|
||||
for (vluint8_t* sp=m_cp; sp < m_endp;) *rp++ = *sp++; // Overlaps
|
||||
for (vluint8_t* sp = m_cp; sp < m_endp; *rp++ = *sp++) {} // Overlaps
|
||||
m_endp = m_bufp + (m_endp - m_cp);
|
||||
m_cp = m_bufp; // Reset buffer
|
||||
// Read into buffer starting at m_endp
|
||||
while (true) {
|
||||
ssize_t remaining = (m_bufp+bufferSize() - m_endp);
|
||||
if (remaining==0) break;
|
||||
ssize_t remaining = (m_bufp + bufferSize() - m_endp);
|
||||
if (remaining == 0) break;
|
||||
errno = 0;
|
||||
ssize_t got = ::read(m_fd, m_endp, remaining);
|
||||
if (got>0) {
|
||||
if (got > 0) {
|
||||
m_endp += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
} else if (VL_UNCOVERABLE(got < 0)) {
|
||||
if (VL_UNCOVERABLE(errno != EAGAIN && errno != EINTR)) {
|
||||
// LCOV_EXCL_START
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
std::string msg = std::string(__FUNCTION__) + ": " + strerror(errno);
|
||||
VL_FATAL_MT("", 0, "", msg.c_str());
|
||||
close();
|
||||
break;
|
||||
// LCOV_EXCL_STOP
|
||||
}
|
||||
} else { // got==0, EOF
|
||||
// Fill buffer from here to end with NULLs so reader's don't
|
||||
// need to check eof each character.
|
||||
while (m_endp < m_bufp+bufferSize()) *m_endp++ = '\0';
|
||||
while (m_endp < m_bufp + bufferSize()) *m_endp++ = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+38
-37
@@ -34,7 +34,7 @@ protected:
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
bool m_isOpen = false; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
@@ -46,15 +46,15 @@ protected:
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedSerialize);
|
||||
|
||||
public:
|
||||
VerilatedSerialize() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t[bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
}
|
||||
virtual ~VerilatedSerialize() {
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
|
||||
}
|
||||
// METHODS
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
@@ -65,20 +65,20 @@ public:
|
||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||
size_t blk = size;
|
||||
if (blk > bufferInsertSize()) blk = bufferInsertSize();
|
||||
const vluint8_t* __restrict maxp = dp + blk;
|
||||
while (dp < maxp) *m_cp++ = *dp++;
|
||||
for (; dp < maxp; *m_cp++ = *dp++) {}
|
||||
size -= blk;
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
|
||||
private:
|
||||
VerilatedSerialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY(m_cp > (m_bufp+(bufferSize()-bufferInsertSize())))) {
|
||||
flush();
|
||||
}
|
||||
if (VL_UNLIKELY(m_cp > (m_bufp + (bufferSize() - bufferInsertSize())))) flush();
|
||||
return *this; // For function chaining
|
||||
}
|
||||
};
|
||||
@@ -93,8 +93,8 @@ protected:
|
||||
// For speed, keep m_cp as the first member of this structure
|
||||
vluint8_t* m_cp; ///< Current pointer into m_bufp buffer
|
||||
vluint8_t* m_bufp; ///< Output buffer
|
||||
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
||||
bool m_isOpen; ///< True indicates open file/stream
|
||||
vluint8_t* m_endp = nullptr; ///< Last valid byte in m_bufp buffer
|
||||
bool m_isOpen = false; ///< True indicates open file/stream
|
||||
std::string m_filename; ///< Filename, for error messages
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
@@ -107,16 +107,15 @@ protected:
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedDeserialize);
|
||||
|
||||
public:
|
||||
VerilatedDeserialize() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t[bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
m_endp = NULL;
|
||||
}
|
||||
virtual ~VerilatedDeserialize() {
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
|
||||
}
|
||||
// METHODS
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
@@ -124,12 +123,13 @@ public:
|
||||
virtual void close() VL_MT_UNSAFE_ONE { flush(); }
|
||||
virtual void flush() VL_MT_UNSAFE_ONE {}
|
||||
inline VerilatedDeserialize& read(void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE {
|
||||
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
||||
vluint8_t* __restrict dp = static_cast<vluint8_t* __restrict>(datap);
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||
size_t blk = size;
|
||||
if (blk > bufferInsertSize()) blk = bufferInsertSize();
|
||||
const vluint8_t* __restrict maxp = dp + blk;
|
||||
while (dp < maxp) *dp++ = *m_cp++;
|
||||
for (; dp < maxp; *dp++ = *m_cp++) {}
|
||||
size -= blk;
|
||||
}
|
||||
return *this; // For function chaining
|
||||
@@ -137,15 +137,15 @@ public:
|
||||
// Read a datum and compare with expected value
|
||||
VerilatedDeserialize& readAssert(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||
VerilatedDeserialize& readAssert(vluint64_t data) VL_MT_UNSAFE_ONE {
|
||||
return readAssert(&data, sizeof(data)); }
|
||||
return readAssert(&data, sizeof(data));
|
||||
}
|
||||
|
||||
private:
|
||||
bool readDiffers(const void* __restrict datap, size_t size) VL_MT_UNSAFE_ONE;
|
||||
VerilatedDeserialize& bufferCheck() VL_MT_UNSAFE_ONE {
|
||||
// Flush the write buffer if there's not enough space left for new information
|
||||
// We only call this once per vector, so we need enough slop for a very wide "b###" line
|
||||
if (VL_UNLIKELY((m_cp+bufferInsertSize()) > m_endp)) {
|
||||
fill();
|
||||
}
|
||||
if (VL_UNLIKELY((m_cp + bufferInsertSize()) > m_endp)) fill();
|
||||
return *this; // For function chaining
|
||||
}
|
||||
};
|
||||
@@ -156,17 +156,18 @@ private:
|
||||
|
||||
class VerilatedSave : public VerilatedSerialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
int m_fd = -1; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedSave() { m_fd = -1; }
|
||||
virtual ~VerilatedSave() VL_OVERRIDE { close(); }
|
||||
VerilatedSave() {}
|
||||
virtual ~VerilatedSave() override { close(); }
|
||||
// METHODS
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void close() override VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() override VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -175,19 +176,20 @@ public:
|
||||
|
||||
class VerilatedRestore : public VerilatedDeserialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
int m_fd = -1; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedRestore() { m_fd = -1; }
|
||||
virtual ~VerilatedRestore() VL_OVERRIDE { close(); }
|
||||
VerilatedRestore() {}
|
||||
virtual ~VerilatedRestore() override { close(); }
|
||||
|
||||
// METHODS
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
|
||||
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
|
||||
virtual void close() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() VL_OVERRIDE VL_MT_UNSAFE_ONE {}
|
||||
virtual void fill() VL_OVERRIDE VL_MT_UNSAFE_ONE;
|
||||
virtual void close() override VL_MT_UNSAFE_ONE;
|
||||
virtual void flush() override VL_MT_UNSAFE_ONE {}
|
||||
virtual void fill() override VL_MT_UNSAFE_ONE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
@@ -250,10 +252,9 @@ VerilatedSerialize& operator<<(VerilatedSerialize& os, VlAssocArray<T_Key, T_Val
|
||||
os << rhs.atDefault();
|
||||
vluint32_t len = rhs.size();
|
||||
os << len;
|
||||
for (typename VlAssocArray<T_Key, T_Value>::const_iterator it = rhs.begin();
|
||||
it != rhs.end(); ++it) {
|
||||
T_Key index = it->first; // Copy to get around const_iterator
|
||||
T_Value value = it->second;
|
||||
for (const auto& i : rhs) {
|
||||
T_Key index = i.first; // Copy to get around const_iterator
|
||||
T_Value value = i.second;
|
||||
os << index << value;
|
||||
}
|
||||
return os;
|
||||
|
||||
+103
-77
@@ -29,20 +29,31 @@
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <vector>
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator range
|
||||
/// Thread safety: Assume is constructed only with model, then any number of readers
|
||||
|
||||
// See also V3Ast::VNumRange
|
||||
class VerilatedRange {
|
||||
int m_left;
|
||||
int m_right;
|
||||
int m_left;
|
||||
int m_right;
|
||||
|
||||
protected:
|
||||
friend class VerilatedVarProps;
|
||||
friend class VerilatedScope;
|
||||
VerilatedRange() : m_left(0), m_right(0) {}
|
||||
VerilatedRange(int left, int right) : m_left(left), m_right(right) {}
|
||||
void init(int left, int right) { m_left=left; m_right=right; }
|
||||
VerilatedRange()
|
||||
: m_left{0}
|
||||
, m_right{0} {}
|
||||
VerilatedRange(int left, int right)
|
||||
: m_left{left}
|
||||
, m_right{right} {}
|
||||
void init(int left, int right) {
|
||||
m_left = left;
|
||||
m_right = right;
|
||||
}
|
||||
|
||||
public:
|
||||
~VerilatedRange() {}
|
||||
int left() const { return m_left; }
|
||||
@@ -50,7 +61,8 @@ public:
|
||||
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 {
|
||||
return (VL_LIKELY(m_left>=m_right) ? (m_left-m_right+1) : (m_right-m_left+1)); }
|
||||
return (VL_LIKELY(m_left >= m_right) ? (m_left - m_right + 1) : (m_right - m_left + 1));
|
||||
}
|
||||
int increment() const { return (m_left >= m_right) ? 1 : -1; }
|
||||
};
|
||||
|
||||
@@ -62,71 +74,77 @@ class VerilatedVarProps {
|
||||
// TYPES
|
||||
enum { MAGIC = 0xddc4f829 };
|
||||
// MEMBERS
|
||||
const vluint32_t m_magic; // Magic number
|
||||
const VerilatedVarType m_vltype; // Data type
|
||||
const VerilatedVarFlags m_vlflags; // Direction
|
||||
const int m_pdims; // Packed dimensions
|
||||
const int m_udims; // Unpacked dimensions
|
||||
VerilatedRange m_packed; // Packed array range
|
||||
VerilatedRange m_unpacked[3]; // Unpacked array range
|
||||
const vluint32_t m_magic; // Magic number
|
||||
const VerilatedVarType m_vltype; // Data type
|
||||
const VerilatedVarFlags m_vlflags; // Direction
|
||||
const int m_pdims; // Packed dimensions
|
||||
const int m_udims; // Unpacked dimensions
|
||||
VerilatedRange m_packed; // Packed array range
|
||||
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
|
||||
void initUnpacked(const int* ulims) {
|
||||
for (int i = 0; i < m_udims; ++i) {
|
||||
const int left = ulims ? ulims[2 * i + 0] : 0;
|
||||
const int right = ulims ? ulims[2 * i + 1] : 0;
|
||||
m_unpacked.push_back(VerilatedRange(left, right));
|
||||
}
|
||||
}
|
||||
// CONSTRUCTORS
|
||||
protected:
|
||||
friend class VerilatedScope;
|
||||
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags,
|
||||
int pdims, int udims)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(vlflags), m_pdims(pdims), m_udims(udims) {}
|
||||
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags{vlflags}
|
||||
, m_pdims{pdims}
|
||||
, m_udims{udims} {
|
||||
initUnpacked(nullptr);
|
||||
}
|
||||
|
||||
public:
|
||||
class Unpacked {};
|
||||
// Without packed
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(0) { }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Unpacked, int u0l, int u0r)
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(1) {
|
||||
m_unpacked[0].init(u0l, u0r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Unpacked, int u0l, int u0r, int u1l, int u1r)
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(2) {
|
||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r)
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(0), m_udims(3) {
|
||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); }
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{0}
|
||||
, m_udims{0} {}
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{0}
|
||||
, m_udims{udims} {
|
||||
initUnpacked(ulims);
|
||||
}
|
||||
// With packed
|
||||
class Packed {};
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Packed, int pl, int pr)
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(0), m_packed(pl,pr) { }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Packed, int pl, int pr,
|
||||
Unpacked, int u0l, int u0r)
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(1), m_packed(pl,pr) {
|
||||
m_unpacked[0].init(u0l, u0r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Packed, int pl, int pr,
|
||||
Unpacked, int u0l, int u0r, int u1l, int u1r)
|
||||
: m_magic(MAGIC), m_vltype(vltype), m_vlflags(VerilatedVarFlags(vlflags)),
|
||||
m_pdims(1), m_udims(2), m_packed(pl,pr) {
|
||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags,
|
||||
Packed, int pl, int pr,
|
||||
Unpacked, int u0l, int u0r, int u1l, int u1r, int u2l, int u2r)
|
||||
: m_magic(MAGIC), m_vltype(vltype),
|
||||
m_vlflags(VerilatedVarFlags(vlflags)), m_pdims(1), m_udims(3), m_packed(pl,pr) {
|
||||
m_unpacked[0].init(u0l, u0r); m_unpacked[1].init(u1l, u1r); m_unpacked[2].init(u2l, u2r); }
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{1}
|
||||
, m_udims{0}
|
||||
, m_packed{pl, pr} {}
|
||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
|
||||
int udims, const int* ulims)
|
||||
: m_magic{MAGIC}
|
||||
, m_vltype{vltype}
|
||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
||||
, m_pdims{1}
|
||||
, m_udims{udims}
|
||||
, m_packed{pl, pr} {
|
||||
initUnpacked(ulims);
|
||||
}
|
||||
|
||||
public:
|
||||
~VerilatedVarProps() {}
|
||||
// METHODS
|
||||
bool magicOk() const { return m_magic == MAGIC; }
|
||||
VerilatedVarType vltype() const { return m_vltype; }
|
||||
VerilatedVarFlags vldir() const {
|
||||
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR); }
|
||||
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
|
||||
}
|
||||
vluint32_t entSize() const;
|
||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||
/// DPI compatible C standard layout
|
||||
@@ -137,28 +155,30 @@ public:
|
||||
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
||||
// DPI accessors
|
||||
int left(int dim) const {
|
||||
return dim==0 ? m_packed.left()
|
||||
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].left() : 0;
|
||||
return dim == 0 ? m_packed.left()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left() : 0;
|
||||
}
|
||||
int right(int dim) const {
|
||||
return dim==0 ? m_packed.right()
|
||||
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].right() : 0;
|
||||
return dim == 0 ? m_packed.right()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right() : 0;
|
||||
}
|
||||
int low(int dim) const {
|
||||
return dim==0 ? m_packed.low()
|
||||
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].low() : 0;
|
||||
return dim == 0 ? m_packed.low()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low() : 0;
|
||||
}
|
||||
int high(int dim) const {
|
||||
return dim==0 ? m_packed.high()
|
||||
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].high() : 0;
|
||||
return dim == 0 ? m_packed.high()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high() : 0;
|
||||
}
|
||||
int increment(int dim) const {
|
||||
return dim==0 ? m_packed.increment()
|
||||
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].increment() : 0;
|
||||
return dim == 0
|
||||
? m_packed.increment()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment() : 0;
|
||||
}
|
||||
int elements(int dim) const {
|
||||
return dim==0 ? m_packed.elements()
|
||||
: VL_LIKELY(dim>=1 && dim<=3) ? m_unpacked[dim-1].elements() : 0;
|
||||
return dim == 0
|
||||
? m_packed.elements()
|
||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements() : 0;
|
||||
}
|
||||
/// Total size in bytes (note DPI limited to 4GB)
|
||||
size_t totalSize() const;
|
||||
@@ -176,11 +196,11 @@ class VerilatedDpiOpenVar {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, void* datap)
|
||||
: m_propsp(propsp)
|
||||
, m_datap(datap) {}
|
||||
: m_propsp{propsp}
|
||||
, m_datap{datap} {}
|
||||
VerilatedDpiOpenVar(const VerilatedVarProps* propsp, const void* datap)
|
||||
: m_propsp(propsp)
|
||||
, m_datap(const_cast<void*>(datap)) {}
|
||||
: m_propsp{propsp}
|
||||
, m_datap{const_cast<void*>(datap)} {}
|
||||
~VerilatedDpiOpenVar() {}
|
||||
// METHODS
|
||||
void* datap() const { return m_datap; }
|
||||
@@ -199,7 +219,8 @@ public:
|
||||
int elements(int dim) const { return m_propsp->elements(dim); }
|
||||
size_t totalSize() const { return m_propsp->totalSize(); }
|
||||
void* datapAdjustIndex(void* datap, int dim, int indx) const {
|
||||
return m_propsp->datapAdjustIndex(datap, dim, indx); }
|
||||
return m_propsp->datapAdjustIndex(datap, dim, indx);
|
||||
}
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
@@ -211,12 +232,16 @@ class VerilatedVar : public VerilatedVarProps {
|
||||
void* m_datap; // Location of data
|
||||
const char* m_namep; // Name - slowpath
|
||||
protected:
|
||||
bool m_isParam;
|
||||
friend class VerilatedScope;
|
||||
// CONSTRUCTORS
|
||||
VerilatedVar(const char* namep, void* datap,
|
||||
VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims)
|
||||
: VerilatedVarProps(vltype, vlflags, (dims>0?1:0), ((dims>1)?dims-1:0))
|
||||
, m_datap(datap), m_namep(namep) {}
|
||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||
VerilatedVarFlags vlflags, int dims, bool isParam)
|
||||
: VerilatedVarProps{vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0)}
|
||||
, m_datap{datap}
|
||||
, m_namep{namep}
|
||||
, m_isParam{isParam} {}
|
||||
|
||||
public:
|
||||
~VerilatedVar() {}
|
||||
// ACCESSORS
|
||||
@@ -224,6 +249,7 @@ public:
|
||||
const VerilatedRange& range() const { return packed(); } // Deprecated
|
||||
const VerilatedRange& array() const { return unpacked(); } // Deprecated
|
||||
const char* name() const { return m_namep; }
|
||||
bool isParam() const { return m_isParam; }
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
|
||||
std::atomic<vluint64_t> VlMTaskVertex::s_yields;
|
||||
|
||||
VL_THREAD_LOCAL VlThreadPool::ProfileTrace* VlThreadPool::t_profilep = NULL;
|
||||
VL_THREAD_LOCAL VlThreadPool::ProfileTrace* VlThreadPool::t_profilep = nullptr;
|
||||
|
||||
//=============================================================================
|
||||
// VlMTaskVertex
|
||||
|
||||
VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount)
|
||||
: m_upstreamDepsDone(0),
|
||||
m_upstreamDepCount(upstreamDepCount) {
|
||||
: m_upstreamDepsDone{0}
|
||||
, m_upstreamDepCount{upstreamDepCount} {
|
||||
assert(atomic_is_lock_free(&m_upstreamDepsDone));
|
||||
}
|
||||
|
||||
@@ -36,13 +36,11 @@ VlMTaskVertex::VlMTaskVertex(vluint32_t upstreamDepCount)
|
||||
// VlWorkerThread
|
||||
|
||||
VlWorkerThread::VlWorkerThread(VlThreadPool* poolp, bool profiling)
|
||||
: m_waiting(false)
|
||||
, m_ready_size(0)
|
||||
, m_poolp(poolp)
|
||||
, m_profiling(profiling)
|
||||
, m_exiting(false)
|
||||
// Must init this last -- after setting up fields that it might read:
|
||||
, m_cthread(startWorker, this) {}
|
||||
: m_waiting{false}
|
||||
, m_poolp{poolp}
|
||||
, m_profiling{profiling} // Must init this last -- after setting up fields that it might read:
|
||||
, m_exiting{false}
|
||||
, m_cthread{startWorker, this} {}
|
||||
|
||||
VlWorkerThread::~VlWorkerThread() {
|
||||
m_exiting.store(true, std::memory_order_release);
|
||||
@@ -52,61 +50,51 @@ VlWorkerThread::~VlWorkerThread() {
|
||||
}
|
||||
|
||||
void VlWorkerThread::workerLoop() {
|
||||
if (VL_UNLIKELY(m_profiling)) {
|
||||
m_poolp->setupProfilingClientThread();
|
||||
}
|
||||
if (VL_UNLIKELY(m_profiling)) m_poolp->setupProfilingClientThread();
|
||||
|
||||
ExecRec work;
|
||||
work.m_fnp = NULL;
|
||||
work.m_fnp = nullptr;
|
||||
|
||||
while (true) {
|
||||
if (VL_LIKELY(!work.m_fnp)) {
|
||||
dequeWork(&work);
|
||||
}
|
||||
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_UNLIKELY(m_exiting.load(std::memory_order_acquire))) break;
|
||||
|
||||
if (VL_LIKELY(work.m_fnp)) {
|
||||
work.m_fnp(work.m_evenCycle, work.m_sym);
|
||||
work.m_fnp = NULL;
|
||||
work.m_fnp = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (VL_UNLIKELY(m_profiling)) {
|
||||
m_poolp->tearDownProfilingClientThread();
|
||||
}
|
||||
if (VL_UNLIKELY(m_profiling)) m_poolp->tearDownProfilingClientThread();
|
||||
}
|
||||
|
||||
void VlWorkerThread::startWorker(VlWorkerThread* workerp) {
|
||||
workerp->workerLoop();
|
||||
}
|
||||
void VlWorkerThread::startWorker(VlWorkerThread* workerp) { workerp->workerLoop(); }
|
||||
|
||||
//=============================================================================
|
||||
// VlThreadPool
|
||||
|
||||
VlThreadPool::VlThreadPool(int nThreads, bool profiling)
|
||||
: m_profiling(profiling) {
|
||||
: m_profiling{profiling} {
|
||||
// --threads N passes nThreads=N-1, as the "main" threads counts as 1
|
||||
unsigned cpus = std::thread::hardware_concurrency();
|
||||
if (cpus < nThreads+1) {
|
||||
if (cpus < nThreads + 1) {
|
||||
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+1);
|
||||
" --threads %d; may run slow.\n",
|
||||
cpus, nThreads + 1);
|
||||
}
|
||||
}
|
||||
// Create'em
|
||||
for (int i=0; i<nThreads; ++i) {
|
||||
for (int i = 0; i < nThreads; ++i) {
|
||||
m_workers.push_back(new VlWorkerThread(this, profiling));
|
||||
}
|
||||
// Set up a profile buffer for the current thread too -- on the
|
||||
// assumption that it's the same thread that calls eval and may be
|
||||
// donated to run mtasks during the eval.
|
||||
if (VL_UNLIKELY(m_profiling)) {
|
||||
setupProfilingClientThread();
|
||||
}
|
||||
if (VL_UNLIKELY(m_profiling)) setupProfilingClientThread();
|
||||
}
|
||||
|
||||
VlThreadPool::~VlThreadPool() {
|
||||
@@ -114,15 +102,13 @@ VlThreadPool::~VlThreadPool() {
|
||||
// Each ~WorkerThread will wait for its thread to exit.
|
||||
delete m_workers[i];
|
||||
}
|
||||
if (VL_UNLIKELY(m_profiling)) {
|
||||
tearDownProfilingClientThread();
|
||||
}
|
||||
if (VL_UNLIKELY(m_profiling)) tearDownProfilingClientThread();
|
||||
}
|
||||
|
||||
void VlThreadPool::tearDownProfilingClientThread() {
|
||||
assert(t_profilep);
|
||||
delete t_profilep;
|
||||
t_profilep = NULL;
|
||||
t_profilep = nullptr;
|
||||
}
|
||||
|
||||
void VlThreadPool::setupProfilingClientThread() {
|
||||
@@ -132,73 +118,63 @@ void VlThreadPool::setupProfilingClientThread() {
|
||||
// try not to malloc while collecting profiling.
|
||||
t_profilep->reserve(4096);
|
||||
{
|
||||
VerilatedLockGuard lk(m_mutex);
|
||||
const VerilatedLockGuard lk(m_mutex);
|
||||
m_allProfiles.insert(t_profilep);
|
||||
}
|
||||
}
|
||||
|
||||
void VlThreadPool::profileAppendAll(const VlProfileRec& rec) {
|
||||
VerilatedLockGuard lk(m_mutex);
|
||||
for (ProfileSet::iterator it = m_allProfiles.begin();
|
||||
it != m_allProfiles.end(); ++it) {
|
||||
const VerilatedLockGuard lk(m_mutex);
|
||||
for (const auto& profilep : m_allProfiles) {
|
||||
// Every thread's profile trace gets a copy of rec.
|
||||
(*it)->emplace_back(rec);
|
||||
profilep->emplace_back(rec);
|
||||
}
|
||||
}
|
||||
|
||||
void VlThreadPool::profileDump(const char* filenamep, vluint64_t ticksElapsed) {
|
||||
VerilatedLockGuard lk(m_mutex);
|
||||
const VerilatedLockGuard lk(m_mutex);
|
||||
VL_DEBUG_IF(VL_DBG_MSGF("+prof+threads writing to '%s'\n", filenamep););
|
||||
|
||||
FILE* fp = fopen(filenamep, "w");
|
||||
if (VL_UNLIKELY(!fp)) {
|
||||
VL_FATAL_MT(filenamep, 0, "", "+prof+threads+file file not writable");
|
||||
return;
|
||||
// cppcheck-suppress resourceLeak // bug, doesn't realize fp is nullptr
|
||||
return; // LCOV_EXCL_LINE
|
||||
}
|
||||
|
||||
// TODO Perhaps merge with verilated_coverage output format, so can
|
||||
// have a common merging and reporting tool, etc.
|
||||
fprintf(fp, "VLPROFTHREAD 1.0 # Verilator thread profile dump version 1.0\n");
|
||||
fprintf(fp, "VLPROF arg --threads %" VL_PRI64 "u\n",
|
||||
vluint64_t(m_workers.size()+1));
|
||||
fprintf(fp, "VLPROF arg --threads %" VL_PRI64 "u\n", vluint64_t(m_workers.size() + 1));
|
||||
fprintf(fp, "VLPROF arg +verilator+prof+threads+start+%" VL_PRI64 "u\n",
|
||||
Verilated::profThreadsStart());
|
||||
fprintf(fp, "VLPROF arg +verilator+prof+threads+window+%u\n",
|
||||
Verilated::profThreadsWindow());
|
||||
fprintf(fp, "VLPROF stat yields %" VL_PRI64 "u\n",
|
||||
VlMTaskVertex::yields());
|
||||
fprintf(fp, "VLPROF arg +verilator+prof+threads+window+%u\n", Verilated::profThreadsWindow());
|
||||
fprintf(fp, "VLPROF stat yields %" VL_PRI64 "u\n", VlMTaskVertex::yields());
|
||||
|
||||
vluint32_t thread_id = 0;
|
||||
for (ProfileSet::const_iterator pit = m_allProfiles.begin();
|
||||
pit != m_allProfiles.end(); ++pit) {
|
||||
for (const auto& pi : m_allProfiles) {
|
||||
++thread_id;
|
||||
|
||||
bool printing = false; // False while in warmup phase
|
||||
for (ProfileTrace::const_iterator eit = (*pit)->begin();
|
||||
eit != (*pit)->end(); ++eit) {
|
||||
switch (eit->m_type) {
|
||||
case VlProfileRec::TYPE_BARRIER:
|
||||
for (const auto& ei : *pi) {
|
||||
switch (ei.m_type) {
|
||||
case VlProfileRec::TYPE_BARRIER: //
|
||||
printing = true;
|
||||
break;
|
||||
case VlProfileRec::TYPE_MTASK_RUN:
|
||||
if (!printing) break;
|
||||
fprintf(fp, "VLPROF mtask %d"
|
||||
" start %" VL_PRI64"u end %" VL_PRI64"u elapsed %" VL_PRI64 "u"
|
||||
fprintf(fp,
|
||||
"VLPROF mtask %d"
|
||||
" start %" VL_PRI64 "u end %" VL_PRI64 "u elapsed %" VL_PRI64 "u"
|
||||
" predict_time %u cpu %u on thread %u\n",
|
||||
eit->m_mtaskId,
|
||||
eit->m_startTime,
|
||||
eit->m_endTime,
|
||||
(eit->m_endTime - eit->m_startTime),
|
||||
eit->m_predictTime,
|
||||
eit->m_cpu,
|
||||
thread_id);
|
||||
ei.m_mtaskId, ei.m_startTime, ei.m_endTime,
|
||||
(ei.m_endTime - ei.m_startTime), ei.m_predictTime, ei.m_cpu, thread_id);
|
||||
break;
|
||||
default: assert(false); break; // LCOV_EXCL_LINE
|
||||
}
|
||||
}
|
||||
}
|
||||
fprintf(fp, "VLPROF stat ticks %" VL_PRI64 "u\n",
|
||||
ticksElapsed);
|
||||
fprintf(fp, "VLPROF stat ticks %" VL_PRI64 "u\n", ticksElapsed);
|
||||
|
||||
fclose(fp);
|
||||
}
|
||||
|
||||
+30
-22
@@ -22,15 +22,27 @@
|
||||
#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 <condition_variable>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
|
||||
// clang-format off
|
||||
#if defined(__linux)
|
||||
#include <sched.h> // For sched_getcpu()
|
||||
# include <sched.h> // For sched_getcpu()
|
||||
#endif
|
||||
#if defined(__APPLE__)
|
||||
# include <cpuid.h> // For __cpuid_count()
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
// VlMTaskVertex and VlThreadpool will work with multiple symbol table types.
|
||||
// Since the type is opaque to VlMTaskVertex and VlThreadPool, represent it
|
||||
@@ -115,27 +127,17 @@ public:
|
||||
class VlProfileRec {
|
||||
protected:
|
||||
friend class VlThreadPool;
|
||||
enum VlProfileE {
|
||||
TYPE_MTASK_RUN,
|
||||
TYPE_BARRIER
|
||||
};
|
||||
VlProfileE m_type; // Record type
|
||||
vluint32_t m_mtaskId; // Mtask we're logging
|
||||
vluint32_t m_predictTime; // How long scheduler predicted would take
|
||||
vluint64_t m_startTime; // Tick at start of execution
|
||||
vluint64_t m_endTime; // Tick at end of execution
|
||||
enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER };
|
||||
VlProfileE m_type = TYPE_BARRIER; // Record type
|
||||
vluint32_t m_mtaskId = 0; // Mtask we're logging
|
||||
vluint32_t m_predictTime = 0; // How long scheduler predicted would take
|
||||
vluint64_t m_startTime = 0; // Tick at start of execution
|
||||
vluint64_t m_endTime = 0; // Tick at end of execution
|
||||
unsigned m_cpu; // Execution CPU number (at start anyways)
|
||||
public:
|
||||
class Barrier {};
|
||||
VlProfileRec() {}
|
||||
explicit VlProfileRec(Barrier) {
|
||||
m_type = TYPE_BARRIER;
|
||||
m_mtaskId = 0;
|
||||
m_predictTime = 0;
|
||||
m_startTime = 0;
|
||||
m_endTime = 0;
|
||||
m_cpu = getcpu();
|
||||
}
|
||||
explicit VlProfileRec(Barrier) { m_cpu = getcpu(); }
|
||||
void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) {
|
||||
m_type = VlProfileRec::TYPE_MTASK_RUN;
|
||||
m_mtaskId = mtask;
|
||||
@@ -173,9 +175,14 @@ private:
|
||||
VlExecFnp m_fnp; // Function to execute
|
||||
VlThrSymTab m_sym; // Symbol table to execute
|
||||
bool m_evenCycle; // Even/odd for flag alternation
|
||||
ExecRec() : m_fnp(NULL), m_sym(NULL), m_evenCycle(false) {}
|
||||
ExecRec()
|
||||
: m_fnp{nullptr}
|
||||
, m_sym{nullptr}
|
||||
, m_evenCycle{false} {}
|
||||
ExecRec(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym)
|
||||
: m_fnp(fnp), m_sym(sym), m_evenCycle(evenCycle) {}
|
||||
: m_fnp{fnp}
|
||||
, m_sym{sym}
|
||||
, m_evenCycle{evenCycle} {}
|
||||
};
|
||||
|
||||
// MEMBERS
|
||||
@@ -208,7 +215,7 @@ public:
|
||||
inline void dequeWork(ExecRec* workp) {
|
||||
// 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))) {
|
||||
if (VL_LIKELY(m_ready_size.load(std::memory_order_relaxed))) { //
|
||||
break;
|
||||
}
|
||||
VL_CPU_RELAX();
|
||||
@@ -229,7 +236,7 @@ public:
|
||||
inline void addTask(VlExecFnp fnp, bool evenCycle, VlThrSymTab sym) {
|
||||
bool notify;
|
||||
{
|
||||
VerilatedLockGuard lk(m_mutex);
|
||||
const VerilatedLockGuard lk(m_mutex);
|
||||
m_ready.emplace_back(fnp, evenCycle, sym);
|
||||
m_ready_size.fetch_add(1, std::memory_order_relaxed);
|
||||
notify = m_waiting;
|
||||
@@ -284,6 +291,7 @@ public:
|
||||
// this once to setup profiling state:
|
||||
void setupProfilingClientThread();
|
||||
void tearDownProfilingClientThread();
|
||||
|
||||
private:
|
||||
VL_UNCOPYABLE(VlThreadPool);
|
||||
};
|
||||
|
||||
@@ -0,0 +1,403 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2020 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Tracing functionality common to all formats
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#ifndef _VERILATED_TRACE_H_
|
||||
#define _VERILATED_TRACE_H_ 1
|
||||
|
||||
// clang-format off
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
# include <condition_variable>
|
||||
# include <deque>
|
||||
# include <thread>
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
//=============================================================================
|
||||
// Threaded tracing
|
||||
|
||||
// A simple synchronized first in first out queue
|
||||
template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
|
||||
private:
|
||||
VerilatedMutex m_mutex; // Protects m_queue
|
||||
std::condition_variable_any m_cv;
|
||||
std::deque<T> m_queue VL_GUARDED_BY(m_mutex);
|
||||
|
||||
public:
|
||||
// Put an element at the back of the queue
|
||||
void put(T value) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_queue.push_back(value);
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
// Put an element at the front of the queue
|
||||
void put_front(T value) {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_queue.push_front(value);
|
||||
m_cv.notify_one();
|
||||
}
|
||||
|
||||
// Get an element from the front of the queue. Blocks if none available
|
||||
T get() {
|
||||
VerilatedLockGuard lock(m_mutex);
|
||||
m_cv.wait(lock, [this]() VL_REQUIRES(m_mutex) { return !m_queue.empty(); });
|
||||
assert(!m_queue.empty());
|
||||
T value = m_queue.front();
|
||||
m_queue.pop_front();
|
||||
return value;
|
||||
}
|
||||
|
||||
// Non blocking get
|
||||
bool tryGet(T& result) {
|
||||
const VerilatedLockGuard lockGuard(m_mutex);
|
||||
if (m_queue.empty()) { return false; }
|
||||
result = m_queue.front();
|
||||
m_queue.pop_front();
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Commands used by thread tracing. Anonymous enum in class, as we want
|
||||
// it scoped, but we also want the automatic conversion to integer types.
|
||||
class VerilatedTraceCommand {
|
||||
public:
|
||||
// These must all fit in 4 bit at the moment, as the tracing routines
|
||||
// pack parameters in the top bits.
|
||||
enum : vluint8_t {
|
||||
CHG_BIT_0 = 0x0,
|
||||
CHG_BIT_1 = 0x1,
|
||||
CHG_CDATA = 0x2,
|
||||
CHG_SDATA = 0x3,
|
||||
CHG_IDATA = 0x4,
|
||||
CHG_QDATA = 0x5,
|
||||
CHG_WDATA = 0x6,
|
||||
CHG_DOUBLE = 0x8,
|
||||
// TODO: full..
|
||||
TIME_CHANGE = 0xd,
|
||||
END = 0xe, // End of buffer
|
||||
SHUTDOWN = 0xf // Shutdown worker thread, also marks end of buffer
|
||||
};
|
||||
};
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedTrace
|
||||
|
||||
// VerilatedTrace uses F-bounded polymorphism to access duck-typed
|
||||
// implementations in the format specific derived class, which must be passed
|
||||
// as the type parameter T_Derived
|
||||
template <class T_Derived> class VerilatedTrace {
|
||||
public:
|
||||
//=========================================================================
|
||||
// Generic tracing internals
|
||||
|
||||
typedef void (*initCb_t)(void*, T_Derived*, uint32_t); // Type of init callbacks
|
||||
typedef void (*dumpCb_t)(void*, T_Derived*); // Type of all but init callbacks
|
||||
|
||||
private:
|
||||
struct CallbackRecord {
|
||||
// Note: would make these fields const, but some old STL implementations
|
||||
// (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the
|
||||
// assignment operator on inserting into collections, so they don't work
|
||||
// with const fields...
|
||||
union {
|
||||
initCb_t m_initCb; // The callback function
|
||||
dumpCb_t m_dumpCb; // The callback function
|
||||
};
|
||||
void* m_userp; // The user pointer to pass to the callback (the symbol table)
|
||||
CallbackRecord(initCb_t cb, void* userp)
|
||||
: m_initCb{cb}
|
||||
, m_userp{userp} {}
|
||||
CallbackRecord(dumpCb_t cb, void* userp)
|
||||
: m_dumpCb{cb}
|
||||
, m_userp{userp} {}
|
||||
};
|
||||
|
||||
vluint32_t* m_sigs_oldvalp; ///< Old value store
|
||||
vluint64_t m_timeLastDump; ///< Last time we did a dump
|
||||
std::vector<CallbackRecord> m_initCbs; ///< Routines to initialize traciong
|
||||
std::vector<CallbackRecord> m_fullCbs; ///< Routines to perform full dump
|
||||
std::vector<CallbackRecord> m_chgCbs; ///< Routines to perform incremental dump
|
||||
std::vector<CallbackRecord> m_cleanupCbs; ///< Routines to call at the end of dump
|
||||
bool m_fullDump; ///< Whether a full dump is required on the next call to 'dump'
|
||||
vluint32_t m_nextCode; ///< Next code number to assign
|
||||
vluint32_t m_numSignals; ///< Number of distinct signals
|
||||
vluint32_t m_maxBits; ///< Number of bits in the widest signal
|
||||
std::string m_moduleName; ///< Name of module being trace initialized now
|
||||
char m_scopeEscape;
|
||||
double m_timeRes; ///< Time resolution (ns/ms etc)
|
||||
double m_timeUnit; ///< Time units (ns/ms etc)
|
||||
|
||||
void addCallbackRecord(std::vector<CallbackRecord>& cbVec, CallbackRecord& cbRec);
|
||||
|
||||
// Equivalent to 'this' but is of the sub-type 'T_Derived*'. Use 'self()->'
|
||||
// to access duck-typed functions to avoid a virtual function call.
|
||||
T_Derived* self() { return static_cast<T_Derived*>(this); }
|
||||
|
||||
// Flush any remaining data for this file
|
||||
static void onFlush(void* selfp) VL_MT_UNSAFE_ONE;
|
||||
// Close the file on termination
|
||||
static void onExit(void* selfp) VL_MT_UNSAFE_ONE;
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
// Number of total trace buffers that have been allocated
|
||||
vluint32_t m_numTraceBuffers;
|
||||
|
||||
// Size of trace buffers
|
||||
size_t m_traceBufferSize;
|
||||
|
||||
// Buffers handed to worker for processing
|
||||
VerilatedThreadQueue<vluint32_t*> m_buffersToWorker;
|
||||
// Buffers returned from worker after processing
|
||||
VerilatedThreadQueue<vluint32_t*> m_buffersFromWorker;
|
||||
|
||||
// Get a new trace buffer that can be populated. May block if none available
|
||||
vluint32_t* getTraceBuffer();
|
||||
|
||||
// Write pointer into current buffer
|
||||
vluint32_t* m_traceBufferWritep;
|
||||
|
||||
// End of trace buffer
|
||||
vluint32_t* m_traceBufferEndp;
|
||||
|
||||
// The worker thread itself
|
||||
std::unique_ptr<std::thread> m_workerThread;
|
||||
|
||||
// The function executed by the worker thread
|
||||
void workerThreadMain();
|
||||
|
||||
// Wait until given buffer is placed in m_buffersFromWorker
|
||||
void waitForBuffer(const vluint32_t* bufferp);
|
||||
|
||||
// Shut down and join worker, if it's running, otherwise do nothing
|
||||
void shutdownWorker();
|
||||
#endif
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedTrace);
|
||||
|
||||
protected:
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
|
||||
vluint32_t nextCode() const { return m_nextCode; }
|
||||
vluint32_t numSignals() const { return m_numSignals; }
|
||||
vluint32_t maxBits() const { return m_maxBits; }
|
||||
const std::string& moduleName() const { return m_moduleName; }
|
||||
void fullDump(bool value) { m_fullDump = value; }
|
||||
vluint64_t timeLastDump() { return m_timeLastDump; }
|
||||
|
||||
double timeRes() const { return m_timeRes; }
|
||||
double timeUnit() const { return m_timeUnit; }
|
||||
std::string timeResStr() const;
|
||||
std::string timeUnitStr() const;
|
||||
|
||||
void traceInit() VL_MT_UNSAFE;
|
||||
|
||||
void declCode(vluint32_t code, vluint32_t bits, bool tri);
|
||||
|
||||
/// Is this an escape?
|
||||
bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; }
|
||||
/// Character that splits scopes. Note whitespace are ALWAYS escapes.
|
||||
char scopeEscape() { return m_scopeEscape; }
|
||||
|
||||
void close();
|
||||
void flush();
|
||||
|
||||
//=========================================================================
|
||||
// Virtual functions to be provided by the format specific implementation
|
||||
|
||||
// Called when the trace moves forward to a new time point
|
||||
virtual void emitTimeChange(vluint64_t timeui) = 0;
|
||||
|
||||
// These hooks are called before a full or change based dump is produced.
|
||||
// The return value indicates whether to proceed with the dump.
|
||||
virtual bool preFullDump() = 0;
|
||||
virtual bool preChangeDump() = 0;
|
||||
|
||||
public:
|
||||
//=========================================================================
|
||||
// External interface to client code
|
||||
|
||||
explicit VerilatedTrace();
|
||||
~VerilatedTrace();
|
||||
|
||||
// Set time units (s/ms, defaults to ns)
|
||||
void set_time_unit(const char* unitp);
|
||||
void set_time_unit(const std::string& unit);
|
||||
// Set time resolution (s/ms, defaults to ns)
|
||||
void set_time_resolution(const char* unitp);
|
||||
void set_time_resolution(const std::string& unit);
|
||||
|
||||
// Call
|
||||
void dump(vluint64_t timeui);
|
||||
|
||||
//=========================================================================
|
||||
// Non-hot path internal interface to Verilator generated code
|
||||
|
||||
void addInitCb(initCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
|
||||
void addFullCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
|
||||
void addChgCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
|
||||
void addCleanupCb(dumpCb_t cb, void* userp) VL_MT_UNSAFE_ONE;
|
||||
|
||||
void changeThread() { m_assertOne.changeThread(); }
|
||||
|
||||
void module(const std::string& name) VL_MT_UNSAFE_ONE {
|
||||
m_assertOne.check();
|
||||
m_moduleName = name;
|
||||
}
|
||||
|
||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
||||
|
||||
//=========================================================================
|
||||
// Hot path internal interface to Verilator generated code
|
||||
|
||||
// Implementation note: We rely on the following duck-typed implementations
|
||||
// in the derived class T_Derived. These emit* functions record a format
|
||||
// specific trace entry. Normally one would use pure virtual functions for
|
||||
// these here, but we cannot afford dynamic dispatch for calling these as
|
||||
// this is very hot code during tracing.
|
||||
|
||||
// duck-typed void emitBit(vluint32_t code, CData newval) = 0;
|
||||
// duck-typed void emitCData(vluint32_t code, CData newval, int bits) = 0;
|
||||
// duck-typed void emitSData(vluint32_t code, SData newval, int bits) = 0;
|
||||
// duck-typed void emitIData(vluint32_t code, IData newval, int bits) = 0;
|
||||
// duck-typed void emitQData(vluint32_t code, QData newval, int bits) = 0;
|
||||
// duck-typed void emitWData(vluint32_t code, const WData* newvalp, int bits) = 0;
|
||||
// duck-typed void emitDouble(vluint32_t code, double newval) = 0;
|
||||
|
||||
vluint32_t* oldp(vluint32_t code) { return m_sigs_oldvalp + code; }
|
||||
|
||||
// Write to previous value buffer value and emit trace entry.
|
||||
void fullBit(vluint32_t* oldp, CData newval);
|
||||
void fullCData(vluint32_t* oldp, CData newval, int bits);
|
||||
void fullSData(vluint32_t* oldp, SData newval, int bits);
|
||||
void fullIData(vluint32_t* oldp, IData newval, int bits);
|
||||
void fullQData(vluint32_t* oldp, QData newval, int bits);
|
||||
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits);
|
||||
void fullDouble(vluint32_t* oldp, double newval);
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
// Threaded tracing. Just dump everything in the trace buffer
|
||||
inline void chgBit(vluint32_t code, CData newval) {
|
||||
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_BIT_0 | newval;
|
||||
m_traceBufferWritep[1] = code;
|
||||
m_traceBufferWritep += 2;
|
||||
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||
}
|
||||
inline void chgCData(vluint32_t code, CData newval, int bits) {
|
||||
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_CDATA;
|
||||
m_traceBufferWritep[1] = code;
|
||||
m_traceBufferWritep[2] = newval;
|
||||
m_traceBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||
}
|
||||
inline void chgSData(vluint32_t code, SData newval, int bits) {
|
||||
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_SDATA;
|
||||
m_traceBufferWritep[1] = code;
|
||||
m_traceBufferWritep[2] = newval;
|
||||
m_traceBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||
}
|
||||
inline void chgIData(vluint32_t code, IData newval, int bits) {
|
||||
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_IDATA;
|
||||
m_traceBufferWritep[1] = code;
|
||||
m_traceBufferWritep[2] = newval;
|
||||
m_traceBufferWritep += 3;
|
||||
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||
}
|
||||
inline void chgQData(vluint32_t code, QData newval, int bits) {
|
||||
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_QDATA;
|
||||
m_traceBufferWritep[1] = code;
|
||||
*reinterpret_cast<QData*>(m_traceBufferWritep + 2) = newval;
|
||||
m_traceBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||
}
|
||||
inline void chgWData(vluint32_t code, const WData* newvalp, int bits) {
|
||||
m_traceBufferWritep[0] = (bits << 4) | VerilatedTraceCommand::CHG_WDATA;
|
||||
m_traceBufferWritep[1] = code;
|
||||
m_traceBufferWritep += 2;
|
||||
for (int i = 0; i < (bits + 31) / 32; ++i) { *m_traceBufferWritep++ = newvalp[i]; }
|
||||
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||
}
|
||||
inline void chgDouble(vluint32_t code, double newval) {
|
||||
m_traceBufferWritep[0] = VerilatedTraceCommand::CHG_DOUBLE;
|
||||
m_traceBufferWritep[1] = code;
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
*reinterpret_cast<double*>(m_traceBufferWritep + 2) = newval;
|
||||
m_traceBufferWritep += 4;
|
||||
VL_DEBUG_IF(assert(m_traceBufferWritep <= m_traceBufferEndp););
|
||||
}
|
||||
|
||||
#define CHG(name) chg##name##Impl
|
||||
#else
|
||||
#define CHG(name) chg##name
|
||||
#endif
|
||||
|
||||
// In non-threaded mode, these are called directly by the trace callbacks,
|
||||
// and are called chg*. In threaded mode, they are called by the worker
|
||||
// thread and are called chg*Impl
|
||||
|
||||
// Check previous dumped value of signal. If changed, then emit trace entry
|
||||
inline void CHG(Bit)(vluint32_t* oldp, CData newval) {
|
||||
const vluint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullBit(oldp, newval);
|
||||
}
|
||||
inline void CHG(CData)(vluint32_t* oldp, CData newval, int bits) {
|
||||
const vluint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullCData(oldp, newval, bits);
|
||||
}
|
||||
inline void CHG(SData)(vluint32_t* oldp, SData newval, int bits) {
|
||||
const vluint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullSData(oldp, newval, bits);
|
||||
}
|
||||
inline void CHG(IData)(vluint32_t* oldp, IData newval, int bits) {
|
||||
const vluint32_t diff = *oldp ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullIData(oldp, newval, bits);
|
||||
}
|
||||
inline void CHG(QData)(vluint32_t* oldp, QData newval, int bits) {
|
||||
const vluint64_t diff = *reinterpret_cast<QData*>(oldp) ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullQData(oldp, newval, bits);
|
||||
}
|
||||
inline void CHG(WData)(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||
for (int i = 0; i < (bits + 31) / 32; ++i) {
|
||||
if (VL_UNLIKELY(oldp[i] ^ newvalp[i])) {
|
||||
fullWData(oldp, newvalp, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void CHG(Double)(vluint32_t* oldp, double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
|
||||
}
|
||||
|
||||
#undef CHG
|
||||
};
|
||||
#endif // guard
|
||||
@@ -0,0 +1,643 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2020 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Implementation of tracing functionality common to all trace formats
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
// clang-format off
|
||||
|
||||
#ifndef VL_DERIVED_T
|
||||
# error "This file should be included in trace format implementations"
|
||||
#endif
|
||||
|
||||
#include "verilated_intrinsics.h"
|
||||
#include "verilated_trace.h"
|
||||
|
||||
#if 0
|
||||
# include <iostream>
|
||||
# define VL_TRACE_THREAD_DEBUG(msg) std::cout << "TRACE THREAD: " << msg << std::endl
|
||||
#else
|
||||
# define VL_TRACE_THREAD_DEBUG(msg)
|
||||
#endif
|
||||
|
||||
// clang-format on
|
||||
|
||||
//=============================================================================
|
||||
// Static utility functions
|
||||
|
||||
static double timescaleToDouble(const char* unitp) {
|
||||
char* endp = nullptr;
|
||||
double value = strtod(unitp, &endp);
|
||||
// On error so we allow just "ns" to return 1e-9.
|
||||
if (value == 0.0 && endp == unitp) value = 1;
|
||||
unitp = endp;
|
||||
for (; *unitp && isspace(*unitp); unitp++) {}
|
||||
switch (*unitp) {
|
||||
case 's': value *= 1e1; break;
|
||||
case 'm': value *= 1e-3; break;
|
||||
case 'u': value *= 1e-6; break;
|
||||
case 'n': value *= 1e-9; break;
|
||||
case 'p': value *= 1e-12; break;
|
||||
case 'f': value *= 1e-15; break;
|
||||
case 'a': value *= 1e-18; break;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
static std::string doubleToTimescale(double value) {
|
||||
const char* suffixp = "s";
|
||||
// clang-format off
|
||||
if (value >= 1e0) { suffixp = "s"; value *= 1e0; }
|
||||
else if (value >= 1e-3 ) { suffixp = "ms"; value *= 1e3; }
|
||||
else if (value >= 1e-6 ) { suffixp = "us"; value *= 1e6; }
|
||||
else if (value >= 1e-9 ) { suffixp = "ns"; value *= 1e9; }
|
||||
else if (value >= 1e-12) { suffixp = "ps"; value *= 1e12; }
|
||||
else if (value >= 1e-15) { suffixp = "fs"; value *= 1e15; }
|
||||
else if (value >= 1e-18) { suffixp = "as"; value *= 1e18; }
|
||||
// clang-format on
|
||||
char valuestr[100];
|
||||
sprintf(valuestr, "%3.0f%s", value, suffixp);
|
||||
return valuestr; // Gets converted to string, so no ref to stack
|
||||
}
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
//=========================================================================
|
||||
// Buffer management
|
||||
|
||||
template <> vluint32_t* VerilatedTrace<VL_DERIVED_T>::getTraceBuffer() {
|
||||
vluint32_t* bufferp;
|
||||
// Some jitter is expected, so some number of alternative trace buffers are
|
||||
// required, but don't allocate more than 8 buffers.
|
||||
if (m_numTraceBuffers < 8) {
|
||||
// Allocate a new buffer if none is available
|
||||
if (!m_buffersFromWorker.tryGet(bufferp)) {
|
||||
++m_numTraceBuffers;
|
||||
// Note: over allocate a bit so pointer comparison is well defined
|
||||
// if we overflow only by a small amount
|
||||
bufferp = new vluint32_t[m_traceBufferSize + 16];
|
||||
}
|
||||
} else {
|
||||
// Block until a buffer becomes available
|
||||
bufferp = m_buffersFromWorker.get();
|
||||
}
|
||||
return bufferp;
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::waitForBuffer(const vluint32_t* buffp) {
|
||||
// Slow path code only called on flush/shutdown, so use a simple algorithm.
|
||||
// Collect buffers from worker and stash them until we get the one we want.
|
||||
std::deque<vluint32_t*> stash;
|
||||
do { stash.push_back(m_buffersFromWorker.get()); } while (stash.back() != buffp);
|
||||
// Now put them back in the queue, in the original order.
|
||||
while (!stash.empty()) {
|
||||
m_buffersFromWorker.put_front(stash.back());
|
||||
stash.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Worker thread
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::workerThreadMain() {
|
||||
bool shutdown = false;
|
||||
|
||||
do {
|
||||
vluint32_t* const bufferp = m_buffersToWorker.get();
|
||||
|
||||
VL_TRACE_THREAD_DEBUG("");
|
||||
VL_TRACE_THREAD_DEBUG("Got buffer: " << bufferp);
|
||||
|
||||
const vluint32_t* readp = bufferp;
|
||||
|
||||
while (true) {
|
||||
const vluint32_t cmd = readp[0];
|
||||
const vluint32_t top = cmd >> 4;
|
||||
// Always set this up, as it is almost always needed
|
||||
vluint32_t* const oldp = m_sigs_oldvalp + readp[1];
|
||||
// Note this increment needs to be undone on commands which do not
|
||||
// actually contain a code, but those are the rare cases.
|
||||
readp += 2;
|
||||
|
||||
switch (cmd & 0xF) {
|
||||
//===
|
||||
// CHG_* commands
|
||||
case VerilatedTraceCommand::CHG_BIT_0:
|
||||
VL_TRACE_THREAD_DEBUG("Command CHG_BIT_0 " << top);
|
||||
chgBitImpl(oldp, 0);
|
||||
continue;
|
||||
case VerilatedTraceCommand::CHG_BIT_1:
|
||||
VL_TRACE_THREAD_DEBUG("Command CHG_BIT_1 " << top);
|
||||
chgBitImpl(oldp, 1);
|
||||
continue;
|
||||
case VerilatedTraceCommand::CHG_CDATA:
|
||||
VL_TRACE_THREAD_DEBUG("Command CHG_CDATA " << top);
|
||||
// Bits stored in bottom byte of command
|
||||
chgCDataImpl(oldp, *readp, top);
|
||||
readp += 1;
|
||||
continue;
|
||||
case VerilatedTraceCommand::CHG_SDATA:
|
||||
VL_TRACE_THREAD_DEBUG("Command CHG_SDATA " << top);
|
||||
// Bits stored in bottom byte of command
|
||||
chgSDataImpl(oldp, *readp, top);
|
||||
readp += 1;
|
||||
continue;
|
||||
case VerilatedTraceCommand::CHG_IDATA:
|
||||
VL_TRACE_THREAD_DEBUG("Command CHG_IDATA " << top);
|
||||
// Bits stored in bottom byte of command
|
||||
chgIDataImpl(oldp, *readp, top);
|
||||
readp += 1;
|
||||
continue;
|
||||
case VerilatedTraceCommand::CHG_QDATA:
|
||||
VL_TRACE_THREAD_DEBUG("Command CHG_QDATA " << top);
|
||||
// Bits stored in bottom byte of command
|
||||
chgQDataImpl(oldp, *reinterpret_cast<const QData*>(readp), top);
|
||||
readp += 2;
|
||||
continue;
|
||||
case VerilatedTraceCommand::CHG_WDATA:
|
||||
VL_TRACE_THREAD_DEBUG("Command CHG_WDATA " << top);
|
||||
chgWDataImpl(oldp, readp, top);
|
||||
readp += VL_WORDS_I(top);
|
||||
continue;
|
||||
case VerilatedTraceCommand::CHG_DOUBLE:
|
||||
VL_TRACE_THREAD_DEBUG("Command CHG_DOUBLE " << top);
|
||||
chgDoubleImpl(oldp, *reinterpret_cast<const double*>(readp));
|
||||
readp += 2;
|
||||
continue;
|
||||
|
||||
//===
|
||||
// Rare commands
|
||||
case VerilatedTraceCommand::TIME_CHANGE:
|
||||
VL_TRACE_THREAD_DEBUG("Command TIME_CHANGE " << top);
|
||||
readp -= 1; // No code in this command, undo increment
|
||||
emitTimeChange(*reinterpret_cast<const vluint64_t*>(readp));
|
||||
readp += 2;
|
||||
continue;
|
||||
|
||||
//===
|
||||
// Commands ending this buffer
|
||||
case VerilatedTraceCommand::END: VL_TRACE_THREAD_DEBUG("Command END"); break;
|
||||
case VerilatedTraceCommand::SHUTDOWN:
|
||||
VL_TRACE_THREAD_DEBUG("Command SHUTDOWN");
|
||||
shutdown = true;
|
||||
break;
|
||||
|
||||
//===
|
||||
// Unknown command
|
||||
default: { // LCOV_EXCL_START
|
||||
VL_TRACE_THREAD_DEBUG("Command UNKNOWN");
|
||||
VL_PRINTF_MT("Trace command: 0x%08x\n", cmd);
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Unknown trace command");
|
||||
break;
|
||||
} // LCOV_EXCL_STOP
|
||||
}
|
||||
|
||||
// The above switch will execute 'continue' when necessary,
|
||||
// so if we ever reach here, we are done with the buffer.
|
||||
break;
|
||||
}
|
||||
|
||||
VL_TRACE_THREAD_DEBUG("Returning buffer");
|
||||
|
||||
// Return buffer
|
||||
m_buffersFromWorker.put(bufferp);
|
||||
} while (VL_LIKELY(!shutdown));
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::shutdownWorker() {
|
||||
// If the worker thread is not running, done..
|
||||
if (!m_workerThread) return;
|
||||
|
||||
// Hand an buffer with a shutdown command to the worker thread
|
||||
vluint32_t* const bufferp = getTraceBuffer();
|
||||
bufferp[0] = VerilatedTraceCommand::SHUTDOWN;
|
||||
m_buffersToWorker.put(bufferp);
|
||||
// Wait for it to return
|
||||
waitForBuffer(bufferp);
|
||||
// Join the thread and delete it
|
||||
m_workerThread->join();
|
||||
m_workerThread.reset(nullptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// Life cycle
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::close() {
|
||||
#ifdef VL_TRACE_THREADED
|
||||
shutdownWorker();
|
||||
while (m_numTraceBuffers) {
|
||||
delete[] m_buffersFromWorker.get();
|
||||
m_numTraceBuffers--;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::flush() {
|
||||
#ifdef VL_TRACE_THREADED
|
||||
// Hand an empty buffer to the worker thread
|
||||
vluint32_t* const bufferp = getTraceBuffer();
|
||||
*bufferp = VerilatedTraceCommand::END;
|
||||
m_buffersToWorker.put(bufferp);
|
||||
// Wait for it to be returned. As the processing is in-order,
|
||||
// this ensures all previous buffers have been processed.
|
||||
waitForBuffer(bufferp);
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Callbacks to run on global events
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::onFlush(void* selfp) {
|
||||
// Note this calls 'flush' on the derived class
|
||||
reinterpret_cast<VL_DERIVED_T*>(selfp)->flush();
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::onExit(void* selfp) {
|
||||
// Note this calls 'close' on the derived class
|
||||
reinterpret_cast<VL_DERIVED_T*>(selfp)->close();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedTrace
|
||||
|
||||
template <>
|
||||
VerilatedTrace<VL_DERIVED_T>::VerilatedTrace()
|
||||
: m_sigs_oldvalp{nullptr}
|
||||
, m_timeLastDump{0}
|
||||
, m_fullDump{true}
|
||||
, m_nextCode{0}
|
||||
, m_numSignals{0}
|
||||
, m_maxBits{0}
|
||||
, m_scopeEscape{'.'}
|
||||
, m_timeRes{1e-9}
|
||||
, m_timeUnit {
|
||||
1e-9
|
||||
}
|
||||
#ifdef VL_TRACE_THREADED
|
||||
, m_numTraceBuffers { 0 }
|
||||
#endif
|
||||
{
|
||||
set_time_unit(Verilated::timeunitString());
|
||||
set_time_resolution(Verilated::timeprecisionString());
|
||||
}
|
||||
|
||||
template <> VerilatedTrace<VL_DERIVED_T>::~VerilatedTrace() {
|
||||
if (m_sigs_oldvalp) VL_DO_CLEAR(delete[] m_sigs_oldvalp, m_sigs_oldvalp = nullptr);
|
||||
Verilated::removeFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
|
||||
Verilated::removeExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
|
||||
#ifdef VL_TRACE_THREADED
|
||||
close();
|
||||
#endif
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::traceInit() VL_MT_UNSAFE {
|
||||
m_assertOne.check();
|
||||
|
||||
// Note: It is possible to re-open a trace file (VCD in particular),
|
||||
// so we must reset the next code here, but it must have the same number
|
||||
// of codes on re-open
|
||||
const vluint32_t expectedCodes = nextCode();
|
||||
m_nextCode = 1;
|
||||
m_numSignals = 0;
|
||||
m_maxBits = 0;
|
||||
|
||||
// Call all initialize callbacks, which will:
|
||||
// - Call decl* for each signal
|
||||
// - Store the base code
|
||||
for (vluint32_t i = 0; i < m_initCbs.size(); ++i) {
|
||||
const CallbackRecord& cbr = m_initCbs[i];
|
||||
cbr.m_initCb(cbr.m_userp, self(), nextCode());
|
||||
}
|
||||
|
||||
if (expectedCodes && nextCode() != expectedCodes) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "",
|
||||
"Reopening trace file with different number of signals");
|
||||
}
|
||||
|
||||
// Now that we know the number of codes, allocate space for the buffer
|
||||
// holding previous signal values.
|
||||
if (!m_sigs_oldvalp) m_sigs_oldvalp = new vluint32_t[nextCode()];
|
||||
|
||||
// Set callback so flush/abort will flush this file
|
||||
Verilated::addFlushCb(VerilatedTrace<VL_DERIVED_T>::onFlush, this);
|
||||
Verilated::addExitCb(VerilatedTrace<VL_DERIVED_T>::onExit, this);
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
// Compute trace buffer size. we need to be able to store a new value for
|
||||
// each signal, which is 'nextCode()' entries after the init callbacks
|
||||
// above have been run, plus up to 2 more words of metadata per signal,
|
||||
// plus fixed overhead of 1 for a termination flag and 3 for a time stamp
|
||||
// update.
|
||||
m_traceBufferSize = nextCode() + numSignals() * 2 + 4;
|
||||
|
||||
// Start the worker thread
|
||||
m_workerThread.reset(new std::thread(&VerilatedTrace<VL_DERIVED_T>::workerThreadMain, this));
|
||||
#endif
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_DERIVED_T>::declCode(vluint32_t code, vluint32_t bits, bool tri) {
|
||||
if (!code) {
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", "Internal: internal trace problem, code 0 is illegal");
|
||||
}
|
||||
// Note: The tri-state flag is not used by Verilator, but is here for
|
||||
// compatibility with some foreign code.
|
||||
int codesNeeded = VL_WORDS_I(bits);
|
||||
if (tri) codesNeeded *= 2;
|
||||
m_nextCode = std::max(m_nextCode, code + codesNeeded);
|
||||
++m_numSignals;
|
||||
m_maxBits = std::max(m_maxBits, bits);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Internals available to format specific implementations
|
||||
|
||||
template <> std::string VerilatedTrace<VL_DERIVED_T>::timeResStr() const {
|
||||
return doubleToTimescale(m_timeRes);
|
||||
}
|
||||
|
||||
template <> std::string VerilatedTrace<VL_DERIVED_T>::timeUnitStr() const {
|
||||
return doubleToTimescale(m_timeUnit);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// External interface to client code
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::set_time_unit(const char* unitp) {
|
||||
m_timeUnit = timescaleToDouble(unitp);
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::set_time_unit(const std::string& unit) {
|
||||
set_time_unit(unit.c_str());
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::set_time_resolution(const char* unitp) {
|
||||
m_timeRes = timescaleToDouble(unitp);
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::set_time_resolution(const std::string& unit) {
|
||||
set_time_resolution(unit.c_str());
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::dump(vluint64_t timeui) {
|
||||
m_assertOne.check();
|
||||
if (VL_UNCOVERABLE(m_timeLastDump && timeui <= m_timeLastDump)) { // LCOV_EXCL_START
|
||||
VL_PRINTF_MT("%%Warning: previous dump at t=%" VL_PRI64 "u, requesting t=%" VL_PRI64
|
||||
"u, dump call ignored\n",
|
||||
m_timeLastDump, timeui);
|
||||
return;
|
||||
} // LCOV_EXCL_STOP
|
||||
m_timeLastDump = timeui;
|
||||
|
||||
Verilated::quiesce();
|
||||
|
||||
// Call hook for format specific behaviour
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
if (!preFullDump()) return;
|
||||
} else {
|
||||
if (!preChangeDump()) return;
|
||||
}
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
// Currently only incremental dumps run on the worker thread
|
||||
vluint32_t* bufferp = nullptr;
|
||||
if (VL_LIKELY(!m_fullDump)) {
|
||||
// Get the trace buffer we are about to fill
|
||||
bufferp = getTraceBuffer();
|
||||
m_traceBufferWritep = bufferp;
|
||||
m_traceBufferEndp = bufferp + m_traceBufferSize;
|
||||
|
||||
// Tell worker to update time point
|
||||
m_traceBufferWritep[0] = VerilatedTraceCommand::TIME_CHANGE;
|
||||
*reinterpret_cast<vluint64_t*>(m_traceBufferWritep + 1) = timeui;
|
||||
m_traceBufferWritep += 3;
|
||||
} else {
|
||||
// Update time point
|
||||
flush();
|
||||
emitTimeChange(timeui);
|
||||
}
|
||||
#else
|
||||
// Update time point
|
||||
emitTimeChange(timeui);
|
||||
#endif
|
||||
|
||||
// Run the callbacks
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
m_fullDump = false; // No more need for next dump to be full
|
||||
for (vluint32_t i = 0; i < m_fullCbs.size(); ++i) {
|
||||
const CallbackRecord& cbr = m_fullCbs[i];
|
||||
cbr.m_dumpCb(cbr.m_userp, self());
|
||||
}
|
||||
} else {
|
||||
for (vluint32_t i = 0; i < m_chgCbs.size(); ++i) {
|
||||
const CallbackRecord& cbr = m_chgCbs[i];
|
||||
cbr.m_dumpCb(cbr.m_userp, self());
|
||||
}
|
||||
}
|
||||
|
||||
for (vluint32_t i = 0; i < m_cleanupCbs.size(); ++i) {
|
||||
const CallbackRecord& cbr = m_cleanupCbs[i];
|
||||
cbr.m_dumpCb(cbr.m_userp, self());
|
||||
}
|
||||
|
||||
#ifdef VL_TRACE_THREADED
|
||||
if (VL_LIKELY(bufferp)) {
|
||||
// Mark end of the trace buffer we just filled
|
||||
*m_traceBufferWritep++ = VerilatedTraceCommand::END;
|
||||
|
||||
// Assert no buffer overflow
|
||||
assert(m_traceBufferWritep - bufferp <= m_traceBufferSize);
|
||||
|
||||
// Pass it to the worker thread
|
||||
m_buffersToWorker.put(bufferp);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Non-hot path internal interface to Verilator generated code
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_DERIVED_T>::addCallbackRecord(std::vector<CallbackRecord>& cbVec,
|
||||
CallbackRecord& cbRec) {
|
||||
m_assertOne.check();
|
||||
if (VL_UNCOVERABLE(timeLastDump() != 0)) { // LCOV_EXCL_START
|
||||
std::string msg = (std::string("Internal: ") + __FILE__ + "::" + __FUNCTION__
|
||||
+ " called with already open file");
|
||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
||||
} // LCOV_EXCL_STOP
|
||||
cbVec.push_back(cbRec);
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::addInitCb(initCb_t cb, void* userp) {
|
||||
CallbackRecord cbr(cb, userp);
|
||||
addCallbackRecord(m_initCbs, cbr);
|
||||
}
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::addFullCb(dumpCb_t cb, void* userp) {
|
||||
CallbackRecord cbr(cb, userp);
|
||||
addCallbackRecord(m_fullCbs, cbr);
|
||||
}
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::addChgCb(dumpCb_t cb, void* userp) {
|
||||
CallbackRecord cbr(cb, userp);
|
||||
addCallbackRecord(m_chgCbs, cbr);
|
||||
}
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::addCleanupCb(dumpCb_t cb, void* userp) {
|
||||
CallbackRecord cbr(cb, userp);
|
||||
addCallbackRecord(m_cleanupCbs, cbr);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Hot path internal interface to Verilator generated code
|
||||
|
||||
// These functions must write the new value back into the old value store,
|
||||
// and subsequently call the format specific emit* implementations. Note
|
||||
// that this file must be included in the format specific implementation, so
|
||||
// the emit* functions can be inlined for performance.
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::fullBit(vluint32_t* oldp, CData newval) {
|
||||
*oldp = newval;
|
||||
self()->emitBit(oldp - m_sigs_oldvalp, newval);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_DERIVED_T>::fullCData(vluint32_t* oldp, CData newval, int bits) {
|
||||
*oldp = newval;
|
||||
self()->emitCData(oldp - m_sigs_oldvalp, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_DERIVED_T>::fullSData(vluint32_t* oldp, SData newval, int bits) {
|
||||
*oldp = newval;
|
||||
self()->emitSData(oldp - m_sigs_oldvalp, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_DERIVED_T>::fullIData(vluint32_t* oldp, IData newval, int bits) {
|
||||
*oldp = newval;
|
||||
self()->emitIData(oldp - m_sigs_oldvalp, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_DERIVED_T>::fullQData(vluint32_t* oldp, QData newval, int bits) {
|
||||
*reinterpret_cast<QData*>(oldp) = newval;
|
||||
self()->emitQData(oldp - m_sigs_oldvalp, newval, bits);
|
||||
}
|
||||
|
||||
template <>
|
||||
void VerilatedTrace<VL_DERIVED_T>::fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||
for (int i = 0; i < VL_WORDS_I(bits); ++i) oldp[i] = newvalp[i];
|
||||
self()->emitWData(oldp - m_sigs_oldvalp, newvalp, bits);
|
||||
}
|
||||
|
||||
template <> void VerilatedTrace<VL_DERIVED_T>::fullDouble(vluint32_t* oldp, double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
*reinterpret_cast<double*>(oldp) = newval;
|
||||
self()->emitDouble(oldp - m_sigs_oldvalp, newval);
|
||||
}
|
||||
|
||||
//=========================================================================
|
||||
// Primitives converting binary values to strings...
|
||||
|
||||
// All of these take a destination pointer where the string will be emitted,
|
||||
// and a value to convert. There are a couple of variants for efficiency.
|
||||
|
||||
inline static void cvtCDataToStr(char* dstp, CData value) {
|
||||
#ifdef VL_HAVE_SSE2
|
||||
// Similar to cvtSDataToStr but only the bottom 8 byte lanes are used
|
||||
const __m128i a = _mm_cvtsi32_si128(value);
|
||||
const __m128i b = _mm_unpacklo_epi8(a, a);
|
||||
const __m128i c = _mm_shufflelo_epi16(b, 0);
|
||||
const __m128i m = _mm_set1_epi64x(0x0102040810204080);
|
||||
const __m128i d = _mm_cmpeq_epi8(_mm_and_si128(c, m), m);
|
||||
const __m128i result = _mm_sub_epi8(_mm_set1_epi8('0'), d);
|
||||
_mm_storel_epi64(reinterpret_cast<__m128i*>(dstp), result);
|
||||
#else
|
||||
dstp[0] = '0' | static_cast<char>((value >> 7) & 1);
|
||||
dstp[1] = '0' | static_cast<char>((value >> 6) & 1);
|
||||
dstp[2] = '0' | static_cast<char>((value >> 5) & 1);
|
||||
dstp[3] = '0' | static_cast<char>((value >> 4) & 1);
|
||||
dstp[4] = '0' | static_cast<char>((value >> 3) & 1);
|
||||
dstp[5] = '0' | static_cast<char>((value >> 2) & 1);
|
||||
dstp[6] = '0' | static_cast<char>((value >> 1) & 1);
|
||||
dstp[7] = '0' | static_cast<char>(value & 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void cvtSDataToStr(char* dstp, SData value) {
|
||||
#ifdef VL_HAVE_SSE2
|
||||
// We want each bit in the 16-bit input value to end up in a byte lane
|
||||
// within the 128-bit XMM register. Note that x86 is little-endian and we
|
||||
// want the MSB of the input at the low address, so we will bit-reverse
|
||||
// at the same time.
|
||||
|
||||
// Put value in bottom of 128-bit register a[15:0] = value
|
||||
const __m128i a = _mm_cvtsi32_si128(value);
|
||||
// Interleave bytes with themselves
|
||||
// b[15: 0] = {2{a[ 7:0]}} == {2{value[ 7:0]}}
|
||||
// b[31:16] = {2{a[15:8]}} == {2{value[15:8]}}
|
||||
const __m128i b = _mm_unpacklo_epi8(a, a);
|
||||
// Shuffle bottom 64 bits, note swapping high bytes with low bytes
|
||||
// c[31: 0] = {2{b[31:16]}} == {4{value[15:8}}
|
||||
// c[63:32] = {2{b[15: 0]}} == {4{value[ 7:0}}
|
||||
const __m128i c = _mm_shufflelo_epi16(b, 0x05);
|
||||
// Shuffle whole register
|
||||
// d[ 63: 0] = {2{c[31: 0]}} == {8{value[15:8}}
|
||||
// d[126:54] = {2{c[63:32]}} == {8{value[ 7:0}}
|
||||
const __m128i d = _mm_shuffle_epi32(c, 0x50);
|
||||
// Test each bit within the bytes, this sets each byte lane to 0
|
||||
// if the bit for that lane is 0 and to 0xff if the bit is 1.
|
||||
const __m128i m = _mm_set1_epi64x(0x0102040810204080);
|
||||
const __m128i e = _mm_cmpeq_epi8(_mm_and_si128(d, m), m);
|
||||
// Convert to ASCII by subtracting the masks from ASCII '0':
|
||||
// '0' - 0 is '0', '0' - -1 is '1'
|
||||
const __m128i result = _mm_sub_epi8(_mm_set1_epi8('0'), e);
|
||||
// Store the 16 characters to the un-aligned buffer
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i*>(dstp), result);
|
||||
#else
|
||||
cvtCDataToStr(dstp, value >> 8);
|
||||
cvtCDataToStr(dstp + 8, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void cvtIDataToStr(char* dstp, IData value) {
|
||||
#ifdef VL_HAVE_AVX2
|
||||
// Similar to cvtSDataToStr but the bottom 16-bits are processed in the
|
||||
// top half of the YMM registerss
|
||||
const __m256i a = _mm256_insert_epi32(_mm256_undefined_si256(), value, 0);
|
||||
const __m256i b = _mm256_permute4x64_epi64(a, 0);
|
||||
const __m256i s = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3);
|
||||
const __m256i c = _mm256_shuffle_epi8(b, s);
|
||||
const __m256i m = _mm256_set1_epi64x(0x0102040810204080);
|
||||
const __m256i d = _mm256_cmpeq_epi8(_mm256_and_si256(c, m), m);
|
||||
const __m256i result = _mm256_sub_epi8(_mm256_set1_epi8('0'), d);
|
||||
_mm256_storeu_si256(reinterpret_cast<__m256i*>(dstp), result);
|
||||
#else
|
||||
cvtSDataToStr(dstp, value >> 16);
|
||||
cvtSDataToStr(dstp + 16, value);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline static void cvtQDataToStr(char* dstp, QData value) {
|
||||
cvtIDataToStr(dstp, value >> 32);
|
||||
cvtIDataToStr(dstp + 32, value);
|
||||
}
|
||||
|
||||
#define cvtEDataToStr cvtIDataToStr
|
||||
@@ -1,542 +0,0 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: pre-C++11 replacements for std::unordered_set
|
||||
// and std::unordered_map.
|
||||
//
|
||||
// Code available from: https://verilator.org
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2020 by Wilson Snyder. This program is free software; you
|
||||
// can redistribute it and/or modify it under the terms of either the GNU
|
||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||
// Version 2.0.
|
||||
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
//*************************************************************************
|
||||
// This file has clones of the std::unordered_set and std::unordered_map
|
||||
// hash table types. They are here so that Verilator can use hash tables
|
||||
// in pre-C++11 compilers, and the same client code can link against the
|
||||
// std:: types when they are available.
|
||||
//
|
||||
// The implementations in this file do not implement the complete APIs
|
||||
// of the std:: types. Nor are they correct in every detail,
|
||||
// notably, the const_iterators do not enforce constness. We can extend
|
||||
// these implementations to cover more of the std API as needed.
|
||||
//
|
||||
// TODO: In the future, when Verilator requires C++11 to compile,
|
||||
// remove this entire file and switch to the std:: types.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3_UNORDERED_SET_MAP_H_
|
||||
#define _V3_UNORDERED_SET_MAP_H_
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <list>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
// Abstract 'vl_hash' and 'vl_equal_to' templates.
|
||||
template <typename T> struct vl_hash {
|
||||
size_t operator()(const T& k) const;
|
||||
};
|
||||
|
||||
template <typename T> struct vl_equal_to {
|
||||
bool operator()(const T& a, const T& b) const;
|
||||
};
|
||||
|
||||
// Specializations of 'vl_hash' and 'vl_equal_to'.
|
||||
inline size_t vl_hash_bytes(const void* vbufp, size_t nbytes) {
|
||||
const vluint8_t* bufp = static_cast<const vluint8_t*>(vbufp);
|
||||
size_t hash = 0;
|
||||
for (size_t i = 0; i < nbytes; i++) {
|
||||
hash = bufp[i] + 31u * hash; // the K&R classic!
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
template <> inline size_t
|
||||
vl_hash<unsigned int>::operator()(const unsigned int& k) const {
|
||||
return k;
|
||||
}
|
||||
|
||||
template <> inline bool
|
||||
vl_equal_to<unsigned int>::operator()(const unsigned int& a,
|
||||
const unsigned int& b) const {
|
||||
return a == b;
|
||||
}
|
||||
|
||||
template <> inline size_t
|
||||
vl_hash<std::string>::operator()(const std::string& k) const {
|
||||
return vl_hash_bytes(k.data(), k.size());
|
||||
}
|
||||
|
||||
template <> inline bool
|
||||
vl_equal_to<std::string>::operator()(const std::string& a,
|
||||
const std::string& b) const {
|
||||
// Don't scan the strings if the sizes are different.
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
return (0 == a.compare(b)); // Must scan.
|
||||
}
|
||||
|
||||
template <typename T> struct vl_hash<T*> {
|
||||
size_t operator()(T* kp) const {
|
||||
return ((sizeof(size_t) == sizeof(kp))
|
||||
? reinterpret_cast<size_t>(kp)
|
||||
: vl_hash_bytes(&kp, sizeof(kp)));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> struct vl_equal_to<T*> {
|
||||
bool operator()(T* ap, T* bp) const {
|
||||
return ap == bp;
|
||||
}
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
//
|
||||
/// Functional clone of the std::unordered_set hash table.
|
||||
template <class T_Key,
|
||||
class T_Hash = vl_hash<T_Key>,
|
||||
class T_Equal = vl_equal_to<T_Key> >
|
||||
class vl_unordered_set {
|
||||
public:
|
||||
// TYPES
|
||||
typedef std::list<T_Key> Bucket;
|
||||
enum RehashType { GROW, SHRINK };
|
||||
|
||||
template <class KK, class VV,
|
||||
class HH, class EQ> friend class vl_unordered_map;
|
||||
|
||||
class iterator {
|
||||
protected:
|
||||
// MEMBERS
|
||||
size_t m_bucketIdx; // Bucket this iterator points into
|
||||
typename Bucket::iterator m_bit; // Bucket-local iterator
|
||||
const vl_unordered_set* m_setp; // The containing set
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
iterator(size_t bucketIdx, typename Bucket::iterator bit,
|
||||
const vl_unordered_set* setp)
|
||||
: m_bucketIdx(bucketIdx), m_bit(bit), m_setp(setp) {}
|
||||
|
||||
// METHODS
|
||||
const T_Key& operator*() const {
|
||||
return *m_bit;
|
||||
}
|
||||
// This should really be 'const T_Key*' type for unordered_set,
|
||||
// however this iterator is shared with unordered_map whose
|
||||
// operator-> returns a non-const ValueType*, so keep this
|
||||
// non-const to avoid having to define a whole separate iterator
|
||||
// for unordered_map.
|
||||
T_Key* operator->() const {
|
||||
return &(*m_bit);
|
||||
}
|
||||
bool operator==(const iterator& other) const {
|
||||
return ((m_bucketIdx == other.m_bucketIdx)
|
||||
&& (m_bit == other.m_bit));
|
||||
}
|
||||
bool operator!=(const iterator& other) const {
|
||||
return (!this->operator==(other));
|
||||
}
|
||||
void advanceUntilValid() {
|
||||
while (true) {
|
||||
if (m_bit != m_setp->m_bucketsp[m_bucketIdx].end()) {
|
||||
// Valid iterator in this bucket; we're done.
|
||||
return;
|
||||
}
|
||||
|
||||
// Try the next bucket?
|
||||
m_bucketIdx++;
|
||||
if (m_bucketIdx == m_setp->numBuckets()) {
|
||||
// Ran past the end of buckets, set to end().
|
||||
*this = m_setp->end();
|
||||
return;
|
||||
}
|
||||
m_bit = m_setp->m_bucketsp[m_bucketIdx].begin();
|
||||
}
|
||||
}
|
||||
void operator++() {
|
||||
++m_bit;
|
||||
advanceUntilValid();
|
||||
}
|
||||
|
||||
typename Bucket::iterator bit() const { return m_bit; }
|
||||
};
|
||||
|
||||
// TODO: there's no real const enforcement on the 'const_iterator'.
|
||||
typedef iterator const_iterator;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
size_t m_numElements; // Number of entries present.
|
||||
size_t m_log2Buckets; // Log-base-2 of the number of buckets.
|
||||
mutable Bucket* m_bucketsp; // Hash table buckets. May be NULL;
|
||||
// // we'll allocate it on the fly when
|
||||
// // the first entries are created.
|
||||
Bucket m_emptyBucket; // A fake bucket, used to construct end().
|
||||
T_Hash m_hash; // Hash function provider.
|
||||
T_Equal m_equal; // Equal-to function provider.
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
vl_unordered_set()
|
||||
: m_numElements(0)
|
||||
, m_log2Buckets(initLog2Buckets())
|
||||
, m_bucketsp(NULL)
|
||||
, m_hash()
|
||||
, m_equal() {}
|
||||
|
||||
vl_unordered_set(const vl_unordered_set& other)
|
||||
: m_numElements(other.m_numElements)
|
||||
, m_log2Buckets(other.m_log2Buckets)
|
||||
, m_bucketsp(NULL)
|
||||
, m_hash()
|
||||
, m_equal() {
|
||||
if (other.m_bucketsp) {
|
||||
m_bucketsp = new Bucket[numBuckets()];
|
||||
for (size_t i = 0; i < numBuckets(); i++) {
|
||||
m_bucketsp[i] = other.m_bucketsp[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
~vl_unordered_set() {
|
||||
VL_DO_DANGLING(delete [] m_bucketsp, m_bucketsp);
|
||||
}
|
||||
|
||||
vl_unordered_set& operator=(const vl_unordered_set& other) {
|
||||
if (this != &other) {
|
||||
clear();
|
||||
delete [] m_bucketsp;
|
||||
m_numElements = other.m_numElements;
|
||||
m_log2Buckets = other.m_log2Buckets;
|
||||
if (other.m_bucketsp) {
|
||||
m_bucketsp = new Bucket[numBuckets()];
|
||||
for (size_t i = 0; i < numBuckets(); i++) {
|
||||
m_bucketsp[i] = other.m_bucketsp[i];
|
||||
}
|
||||
} else {
|
||||
m_bucketsp = NULL;
|
||||
}
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// METHODS
|
||||
static size_t initLog2Buckets() { return 4; }
|
||||
|
||||
iterator begin() {
|
||||
if (m_numElements) {
|
||||
initBuckets();
|
||||
iterator result = iterator(0, m_bucketsp[0].begin(), this);
|
||||
result.advanceUntilValid();
|
||||
return result;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
const_iterator begin() const {
|
||||
if (m_numElements) {
|
||||
initBuckets();
|
||||
const_iterator result = iterator(0, m_bucketsp[0].begin(), this);
|
||||
result.advanceUntilValid();
|
||||
return result;
|
||||
}
|
||||
return end();
|
||||
}
|
||||
const_iterator end() const {
|
||||
return iterator(VL_ULL(0xFFFFFFFFFFFFFFFF),
|
||||
const_cast<Bucket&>(m_emptyBucket).begin(), this);
|
||||
}
|
||||
|
||||
bool empty() const { return m_numElements == 0; }
|
||||
|
||||
size_t size() const { return m_numElements; }
|
||||
|
||||
size_t count(const T_Key& key) const {
|
||||
return (find(key) == end()) ? 0 : 1;
|
||||
}
|
||||
|
||||
size_t hashToBucket(size_t hashVal) const {
|
||||
return hashToBucket(hashVal, m_log2Buckets);
|
||||
}
|
||||
static size_t hashToBucket(size_t hashVal, unsigned log2Buckets) {
|
||||
// Fibonacci hashing
|
||||
// See https://probablydance.com/2018/06/16/fibonacci-hashing-the-optimization-that-the-world-forgot-or-a-better-alternative-to-integer-modulo/
|
||||
//
|
||||
// * The magic numbers below are UINT_MAX/phi where phi is the
|
||||
// golden ratio number (1.618...) for either 64- or 32-bit
|
||||
// values of UINT_MAX.
|
||||
//
|
||||
// * Fibonacci hashing mixes the result of the client's hash
|
||||
// function further. This permits the use of very fast client
|
||||
// hash funcs (like just returning the int or pointer value as
|
||||
// is!) and tolerates crappy client hash functions pretty well.
|
||||
size_t mult = hashVal * ((sizeof(size_t) == 8)
|
||||
? VL_ULL(11400714819323198485)
|
||||
: 2654435769lu);
|
||||
size_t result = (mult >> (((sizeof(size_t) == 8)
|
||||
? 64 : 32) - log2Buckets));
|
||||
return result;
|
||||
}
|
||||
|
||||
iterator find_internal(const T_Key& key, size_t& bucketIdxOut) {
|
||||
size_t hash = m_hash.operator()(key);
|
||||
bucketIdxOut = hashToBucket(hash);
|
||||
initBuckets();
|
||||
Bucket* bucketp = &m_bucketsp[bucketIdxOut];
|
||||
|
||||
for (typename Bucket::iterator it = bucketp->begin();
|
||||
it != bucketp->end(); ++it) {
|
||||
if (m_equal.operator()(*it, key)) {
|
||||
return iterator(bucketIdxOut, it, this);
|
||||
}
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
const_iterator find(const T_Key& key) const {
|
||||
size_t bucketIdx;
|
||||
return const_cast<vl_unordered_set*>(this)->find_internal(key,
|
||||
bucketIdx);
|
||||
}
|
||||
|
||||
iterator find(const T_Key& key) {
|
||||
size_t bucketIdx;
|
||||
return find_internal(key, bucketIdx);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(const T_Key& val) {
|
||||
size_t bucketIdx;
|
||||
iterator existIt = find_internal(val, bucketIdx);
|
||||
if (existIt != end()) {
|
||||
// Collision with existing element.
|
||||
//
|
||||
// An element may be inserted only if it is not
|
||||
// equal to an existing element. So fail.
|
||||
return std::pair<iterator, bool>(end(), false);
|
||||
}
|
||||
|
||||
// No collision, so insert it.
|
||||
m_numElements++;
|
||||
|
||||
m_bucketsp[bucketIdx].push_front(val);
|
||||
|
||||
// Compute result iterator. This pointer will be valid
|
||||
// if we don't rehash:
|
||||
iterator result_it(bucketIdx, m_bucketsp[bucketIdx].begin(), this);
|
||||
|
||||
if (needToRehash(GROW)) {
|
||||
rehash(GROW);
|
||||
// ... since we rehashed, do a lookup to get the result iterator.
|
||||
result_it = find(val);
|
||||
}
|
||||
|
||||
return std::pair<iterator, bool>(result_it, true);
|
||||
}
|
||||
|
||||
iterator erase(iterator it) {
|
||||
iterator next_it = it;
|
||||
++next_it;
|
||||
erase(*it);
|
||||
return next_it;
|
||||
}
|
||||
|
||||
size_t erase(const T_Key& key) {
|
||||
size_t bucketIdx;
|
||||
iterator it = find_internal(key, bucketIdx);
|
||||
if (it != end()) {
|
||||
m_bucketsp[bucketIdx].erase(it.bit());
|
||||
m_numElements--;
|
||||
// Rehashing to handle a shrinking data set is important
|
||||
// for the Scoreboard in V3Partition, which begins tracking
|
||||
// a huge number of vertices and then tracks a successively
|
||||
// smaller number over time.
|
||||
if (needToRehash(SHRINK)) {
|
||||
rehash(SHRINK);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
if (m_bucketsp) {
|
||||
delete[] m_bucketsp;
|
||||
m_bucketsp = NULL;
|
||||
}
|
||||
m_numElements = 0;
|
||||
m_log2Buckets = initLog2Buckets();
|
||||
}
|
||||
|
||||
private:
|
||||
size_t numBuckets() const { return (VL_ULL(1) << m_log2Buckets); }
|
||||
|
||||
Bucket* getBucket(size_t idx) {
|
||||
initBuckets();
|
||||
return &m_bucketsp[idx];
|
||||
}
|
||||
|
||||
void initBuckets() const {
|
||||
if (!m_bucketsp) m_bucketsp = new Bucket[numBuckets()];
|
||||
}
|
||||
|
||||
bool needToRehash(RehashType rt) const {
|
||||
if (rt == GROW) {
|
||||
return ((4 * numBuckets()) < m_numElements);
|
||||
} else {
|
||||
return (numBuckets() > (4 * m_numElements));
|
||||
}
|
||||
}
|
||||
|
||||
void rehash(RehashType rt) {
|
||||
size_t new_log2Buckets;
|
||||
if (rt == GROW) {
|
||||
new_log2Buckets = m_log2Buckets + 2;
|
||||
} else {
|
||||
if (m_log2Buckets <= 4) {
|
||||
// On shrink, saturate m_log2Buckets at its
|
||||
// initial size of 2^4 == 16 buckets. Don't risk
|
||||
// underflowing!
|
||||
return;
|
||||
}
|
||||
new_log2Buckets = m_log2Buckets - 2;
|
||||
}
|
||||
|
||||
size_t new_num_buckets = VL_ULL(1) << new_log2Buckets;
|
||||
Bucket* new_bucketsp = new Bucket[new_num_buckets];
|
||||
|
||||
for (size_t i = 0; i < numBuckets(); i++) {
|
||||
while (!m_bucketsp[i].empty()) {
|
||||
typename Bucket::iterator bit = m_bucketsp[i].begin();
|
||||
size_t hash = m_hash.operator()(*bit);
|
||||
size_t new_idx = hashToBucket(hash, new_log2Buckets);
|
||||
// Avoid mallocing one list elem and freeing another;
|
||||
// splice just moves it over.
|
||||
new_bucketsp[new_idx].splice(new_bucketsp[new_idx].begin(),
|
||||
m_bucketsp[i], bit);
|
||||
}
|
||||
}
|
||||
|
||||
delete[] m_bucketsp;
|
||||
m_bucketsp = new_bucketsp;
|
||||
m_log2Buckets = new_log2Buckets;
|
||||
}
|
||||
};
|
||||
|
||||
//===================================================================
|
||||
//
|
||||
/// Functional clone of the std::unordered_map hash table.
|
||||
template <class T_Key,
|
||||
class T_Value,
|
||||
class T_Hash = vl_hash<T_Key>,
|
||||
class T_Equal = vl_equal_to<T_Key> >
|
||||
class vl_unordered_map {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::pair<T_Key, T_Value> KeyValPair;
|
||||
|
||||
class KeyHash {
|
||||
private:
|
||||
T_Hash key_hash;
|
||||
public:
|
||||
KeyHash() {}
|
||||
size_t operator()(const KeyValPair& kv_pair) const {
|
||||
return key_hash.operator()(kv_pair.first);
|
||||
}
|
||||
};
|
||||
|
||||
class KeyEqual {
|
||||
private:
|
||||
T_Equal key_eq;
|
||||
public:
|
||||
KeyEqual() {}
|
||||
bool operator()(const KeyValPair& kv_a, const KeyValPair& kv_b) const {
|
||||
return key_eq.operator()(kv_a.first, kv_b.first);
|
||||
}
|
||||
};
|
||||
|
||||
// MEMBERS
|
||||
typedef vl_unordered_set<KeyValPair, KeyHash, KeyEqual> MapSet;
|
||||
MapSet m_set; // Wrap this vl_unordered_set which holds all state.
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
vl_unordered_map() {}
|
||||
~vl_unordered_map() {}
|
||||
|
||||
typedef typename MapSet::iterator iterator;
|
||||
typedef typename MapSet::const_iterator const_iterator;
|
||||
|
||||
// METHODS
|
||||
iterator begin() { return m_set.begin(); }
|
||||
const_iterator begin() const { return m_set.begin(); }
|
||||
const_iterator end() const { return m_set.end(); }
|
||||
bool empty() const { return m_set.empty(); }
|
||||
iterator find(const T_Key& k) {
|
||||
// We can't assume that T_Value() is defined.
|
||||
// ie, this does not work:
|
||||
// return m_set.find(std::make_pair(k, T_Value()));
|
||||
|
||||
// So, do this instead:
|
||||
T_Hash mapHash;
|
||||
T_Equal mapEq;
|
||||
size_t hash = mapHash.operator()(k);
|
||||
size_t bucketIdxOut = m_set.hashToBucket(hash);
|
||||
typename MapSet::Bucket* bucketp = m_set.getBucket(bucketIdxOut);
|
||||
|
||||
for (typename MapSet::Bucket::iterator it = bucketp->begin();
|
||||
it != bucketp->end(); ++it) {
|
||||
if (mapEq.operator()(it->first, k)) {
|
||||
return iterator(bucketIdxOut, it, &m_set);
|
||||
}
|
||||
}
|
||||
return end();
|
||||
}
|
||||
const_iterator find(const T_Key& k) const {
|
||||
return const_cast<vl_unordered_map*>(this)->find(k);
|
||||
}
|
||||
std::pair<iterator, bool> insert(const KeyValPair& val) {
|
||||
return m_set.insert(val);
|
||||
}
|
||||
iterator erase(iterator it) { return m_set.erase(it); }
|
||||
size_t erase(const T_Key& k) {
|
||||
iterator it = find(k);
|
||||
if (it == end()) { return 0; }
|
||||
m_set.erase(it);
|
||||
return 1;
|
||||
}
|
||||
T_Value& operator[](const T_Key& k) {
|
||||
// Here we can assume T_Value() is defined, as
|
||||
// std::unordered_map::operator[] relies on it too.
|
||||
KeyValPair dummy = std::make_pair(k, T_Value());
|
||||
iterator it = m_set.find(dummy);
|
||||
if (it == m_set.end()) {
|
||||
it = m_set.insert(dummy).first;
|
||||
}
|
||||
// For the 'set', it's generally not safe to modify
|
||||
// the value after deref. For the 'map' though, we know
|
||||
// it's safe to modify the value field and we can allow it:
|
||||
return it->second;
|
||||
}
|
||||
T_Value& at(const T_Key& k) {
|
||||
iterator it = find(k);
|
||||
if (it == end()) { throw std::out_of_range("sorry"); }
|
||||
return it->second;
|
||||
}
|
||||
const T_Value& at(const T_Key& k) const {
|
||||
iterator it = find(k);
|
||||
if (it == end()) { throw std::out_of_range("sorry"); }
|
||||
return it->second;
|
||||
}
|
||||
void clear() { m_set.clear(); }
|
||||
size_t size() const { return m_set.size(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
+449
-384
File diff suppressed because it is too large
Load Diff
+189
-285
@@ -20,15 +20,14 @@
|
||||
#ifndef _VERILATED_VCD_C_H_
|
||||
#define _VERILATED_VCD_C_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_trace.h"
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class VerilatedVcd;
|
||||
class VerilatedVcdCallInfo;
|
||||
|
||||
// SPDIFF_ON
|
||||
//=============================================================================
|
||||
@@ -37,74 +36,48 @@ class VerilatedVcdCallInfo;
|
||||
|
||||
class VerilatedVcdFile {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
int m_fd = 0; ///< File descriptor we're writing to
|
||||
public:
|
||||
// METHODS
|
||||
VerilatedVcdFile()
|
||||
: m_fd(0) {}
|
||||
VerilatedVcdFile() {}
|
||||
virtual ~VerilatedVcdFile() {}
|
||||
virtual bool open(const std::string& name) VL_MT_UNSAFE;
|
||||
virtual void close() VL_MT_UNSAFE;
|
||||
virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdSig
|
||||
/// Internal data on one signal being traced.
|
||||
|
||||
class VerilatedVcdSig {
|
||||
protected:
|
||||
friend class VerilatedVcd;
|
||||
vluint32_t m_code; ///< VCD file code number
|
||||
int m_bits; ///< Size of value in bits
|
||||
VerilatedVcdSig(vluint32_t code, int bits)
|
||||
: m_code(code)
|
||||
, m_bits(bits) {}
|
||||
public:
|
||||
~VerilatedVcdSig() {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluint32_t code);
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcd
|
||||
/// Base class to create a Verilator VCD dump
|
||||
/// This is an internally used class - see VerilatedVcdC for what to call from applications
|
||||
|
||||
class VerilatedVcd {
|
||||
class VerilatedVcd : public VerilatedTrace<VerilatedVcd> {
|
||||
private:
|
||||
VerilatedVcdFile* m_filep; ///< File we're writing to
|
||||
bool m_fileNewed; ///< m_filep needs destruction
|
||||
bool m_isOpen; ///< True indicates open file
|
||||
bool m_evcd; ///< True for evcd format
|
||||
std::string m_filename; ///< Filename we're writing to (if open)
|
||||
vluint64_t m_rolloverMB; ///< MB of file size to rollover at
|
||||
char m_scopeEscape; ///< Character to separate scope components
|
||||
int m_modDepth; ///< Depth of module hierarchy
|
||||
bool m_fullDump; ///< True indicates dump ignoring if changed
|
||||
vluint32_t m_nextCode; ///< Next code number to assign
|
||||
std::string m_modName; ///< Module name being traced now
|
||||
double m_timeRes; ///< Time resolution (ns/ms etc)
|
||||
double m_timeUnit; ///< Time units (ns/ms etc)
|
||||
vluint64_t m_timeLastDump; ///< Last time we did a dump
|
||||
// Give the superclass access to private bits (to avoid virtual functions)
|
||||
friend class VerilatedTrace<VerilatedVcd>;
|
||||
|
||||
char* m_wrBufp; ///< Output buffer
|
||||
char* m_wrFlushp; ///< Output buffer flush trigger location
|
||||
char* m_writep; ///< Write pointer into output buffer
|
||||
vluint64_t m_wrChunkSize; ///< Output buffer size
|
||||
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
|
||||
//=========================================================================
|
||||
// VCD specific internals
|
||||
|
||||
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
|
||||
typedef std::vector<VerilatedVcdSig> SigVec;
|
||||
SigVec m_sigs; ///< Pointer to signal information
|
||||
typedef std::vector<VerilatedVcdCallInfo*> CallbackVec;
|
||||
CallbackVec m_callbacks; ///< Routines to perform dumping
|
||||
typedef std::map<std::string,std::string> NameMap;
|
||||
NameMap* m_namemapp; ///< List of names for the header
|
||||
VerilatedVcdFile* m_filep; ///< File we're writing to
|
||||
bool m_fileNewed; ///< m_filep needs destruction
|
||||
bool m_isOpen = false; ///< True indicates open file
|
||||
bool m_evcd = false; ///< True for evcd format
|
||||
std::string m_filename; ///< Filename we're writing to (if open)
|
||||
vluint64_t m_rolloverMB = 0; ///< MB of file size to rollover at
|
||||
int m_modDepth = 0; ///< Depth of module hierarchy
|
||||
|
||||
VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread
|
||||
char* m_wrBufp; ///< Output buffer
|
||||
char* m_wrFlushp; ///< Output buffer flush trigger location
|
||||
char* m_writep; ///< Write pointer into output buffer
|
||||
vluint64_t m_wrChunkSize; ///< Output buffer size
|
||||
vluint64_t m_wroteBytes = 0; ///< Number of bytes written to this file
|
||||
|
||||
std::vector<char> m_suffixes; ///< VCD line end string codes + metadata
|
||||
const char* m_suffixesp; ///< Pointer to first element of above
|
||||
|
||||
typedef std::map<std::string, std::string> NameMap;
|
||||
NameMap* m_namemapp = nullptr; ///< List of names for the header
|
||||
|
||||
void bufferResize(vluint64_t minsize);
|
||||
void bufferFlush() VL_MT_UNSAFE_ONE;
|
||||
@@ -126,220 +99,140 @@ private:
|
||||
bool tri, bool bussed, int msb, int lsb);
|
||||
|
||||
void dumpHeader();
|
||||
void dumpPrep(vluint64_t timeui);
|
||||
void dumpFull(vluint64_t timeui);
|
||||
// cppcheck-suppress functionConst
|
||||
void dumpDone();
|
||||
inline void printCode(vluint32_t code) {
|
||||
*m_writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
while (code) {
|
||||
code--;
|
||||
*m_writep++ = static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
}
|
||||
}
|
||||
static std::string stringCode(vluint32_t code) VL_PURE {
|
||||
std::string out;
|
||||
out += static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
while (code) {
|
||||
code--;
|
||||
out += static_cast<char>('!' + code % 94);
|
||||
code /= 94;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
static char* writeCode(char* writep, vluint32_t code);
|
||||
|
||||
void finishLine(vluint32_t code, char* writep);
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcd);
|
||||
|
||||
protected:
|
||||
//=========================================================================
|
||||
// Implementation of VerilatedTrace interface
|
||||
|
||||
// Implementations of protected virtual methods for VerilatedTrace
|
||||
virtual void emitTimeChange(vluint64_t timeui) override;
|
||||
|
||||
// Hooks called from VerilatedTrace
|
||||
virtual bool preFullDump() override { return isOpen(); }
|
||||
virtual bool preChangeDump() override;
|
||||
|
||||
// Implementations of duck-typed methods for VerilatedTrace. These are
|
||||
// called from only one place (namely full*) so always inline them.
|
||||
inline void emitBit(vluint32_t code, CData newval);
|
||||
inline void emitCData(vluint32_t code, CData newval, int bits);
|
||||
inline void emitSData(vluint32_t code, SData newval, int bits);
|
||||
inline void emitIData(vluint32_t code, IData newval, int bits);
|
||||
inline void emitQData(vluint32_t code, QData newval, int bits);
|
||||
inline void emitWData(vluint32_t code, const WData* newvalp, int bits);
|
||||
inline void emitDouble(vluint32_t code, double newval);
|
||||
|
||||
public:
|
||||
explicit VerilatedVcd(VerilatedVcdFile* filep = NULL);
|
||||
//=========================================================================
|
||||
// External interface to client code
|
||||
|
||||
explicit VerilatedVcd(VerilatedVcdFile* filep = nullptr);
|
||||
~VerilatedVcd();
|
||||
/// Routines can only be called from one thread; allow next call from different thread
|
||||
void changeThread() { m_assertOne.changeThread(); }
|
||||
|
||||
// ACCESSORS
|
||||
/// Set size in megabytes after which new file should be created
|
||||
void rolloverMB(vluint64_t rolloverMB) { m_rolloverMB = rolloverMB; }
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
/// Change character that splits scopes. Note whitespace are ALWAYS escapes.
|
||||
void scopeEscape(char flag) { m_scopeEscape = flag; }
|
||||
/// Is this an escape?
|
||||
inline bool isScopeEscape(char c) { return isspace(c) || c == m_scopeEscape; }
|
||||
|
||||
// METHODS
|
||||
void open(const char* filename) VL_MT_UNSAFE_ONE; ///< Open the file; call isOpen() to see if errors
|
||||
void openNext(bool incFilename); ///< Open next data-only file
|
||||
void close() VL_MT_UNSAFE_ONE; ///< Close the file
|
||||
/// Open the file; call isOpen() to see if errors
|
||||
void open(const char* filename) VL_MT_UNSAFE_ONE;
|
||||
/// Open next data-only file
|
||||
void openNext(bool incFilename) VL_MT_UNSAFE_ONE;
|
||||
/// Close the file
|
||||
void close() VL_MT_UNSAFE_ONE;
|
||||
/// Flush any remaining data to this file
|
||||
void flush() VL_MT_UNSAFE_ONE { bufferFlush(); }
|
||||
/// Flush any remaining data from all files
|
||||
static void flush_all() VL_MT_UNSAFE_ONE;
|
||||
void flush() VL_MT_UNSAFE_ONE;
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
|
||||
void set_time_unit(const char* unitp); ///< Set time units (s/ms, defaults to ns)
|
||||
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
|
||||
//=========================================================================
|
||||
// Internal interface to Verilator generated code
|
||||
|
||||
void set_time_resolution(const char* unitp); ///< Set time resolution (s/ms, defaults to ns)
|
||||
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
|
||||
void declBit(vluint32_t code, const char* name, bool array, int arraynum);
|
||||
void declBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declDouble(vluint32_t code, const char* name, bool array, int arraynum);
|
||||
|
||||
double timescaleToDouble(const char* unitp);
|
||||
std::string doubleToTimescale(double value);
|
||||
#ifdef VL_TRACE_VCD_OLD_API
|
||||
//=========================================================================
|
||||
// Note: These are only for testing for backward compatibility with foreign
|
||||
// code and is not used by Verilator. Do not use these as there is no
|
||||
// guarantee of functionality.
|
||||
|
||||
/// Inside dumping routines, called each cycle to make the dump
|
||||
void dump(vluint64_t timeui);
|
||||
/// Call dump with a absolute unscaled time in seconds
|
||||
void dumpSeconds(double secs) { dump(static_cast<vluint64_t>(secs * m_timeRes)); }
|
||||
void declTriBit(vluint32_t code, const char* name, bool array, int arraynum);
|
||||
void declTriBus(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declTriQuad(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||
int lsb);
|
||||
void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb,
|
||||
int lsb);
|
||||
|
||||
/// Inside dumping routines, declare callbacks for tracings
|
||||
void addCallback(VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb,
|
||||
VerilatedVcdCallback_t changecb,
|
||||
void* userthis) VL_MT_UNSAFE_ONE;
|
||||
void fullBit(vluint32_t* oldp, CData newval) { fullBit(oldp - this->oldp(0), newval); }
|
||||
void fullCData(vluint32_t* oldp, CData newval, int bits) {
|
||||
fullBus(oldp - this->oldp(0), newval, bits);
|
||||
}
|
||||
void fullSData(vluint32_t* oldp, SData newval, int bits) {
|
||||
fullBus(oldp - this->oldp(0), newval, bits);
|
||||
}
|
||||
void fullIData(vluint32_t* oldp, IData newval, int bits) {
|
||||
fullBus(oldp - this->oldp(0), newval, bits);
|
||||
}
|
||||
void fullQData(vluint32_t* oldp, QData newval, int bits) {
|
||||
fullQuad(oldp - this->oldp(0), newval, bits);
|
||||
}
|
||||
void fullWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||
fullArray(oldp - this->oldp(0), newvalp, bits);
|
||||
}
|
||||
void fullDouble(vluint32_t* oldp, double newval) { fullDouble(oldp - this->oldp(0), newval); }
|
||||
|
||||
/// Inside dumping routines, declare a module
|
||||
void module(const std::string& name);
|
||||
/// Inside dumping routines, declare a signal
|
||||
void declBit( vluint32_t code, const char* name, bool array, int arraynum);
|
||||
void declBus( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declQuad( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declArray( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declTriBit( vluint32_t code, const char* name, bool array, int arraynum);
|
||||
void declTriBus( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declTriQuad( vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declTriArray(vluint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
|
||||
void declDouble( vluint32_t code, const char* name, bool array, int arraynum);
|
||||
void declFloat( vluint32_t code, const char* name, bool array, int arraynum);
|
||||
// ... other module_start for submodules (based on cell name)
|
||||
inline void chgBit(vluint32_t* oldp, CData newval) { chgBit(oldp - this->oldp(0), newval); }
|
||||
inline void chgCData(vluint32_t* oldp, CData newval, int bits) {
|
||||
chgBus(oldp - this->oldp(0), newval, bits);
|
||||
}
|
||||
inline void chgSData(vluint32_t* oldp, SData newval, int bits) {
|
||||
chgBus(oldp - this->oldp(0), newval, bits);
|
||||
}
|
||||
inline void chgIData(vluint32_t* oldp, IData newval, int bits) {
|
||||
chgBus(oldp - this->oldp(0), newval, bits);
|
||||
}
|
||||
inline void chgQData(vluint32_t* oldp, QData newval, int bits) {
|
||||
chgQuad(oldp - this->oldp(0), newval, bits);
|
||||
}
|
||||
inline void chgWData(vluint32_t* oldp, const WData* newvalp, int bits) {
|
||||
chgArray(oldp - this->oldp(0), newvalp, bits);
|
||||
}
|
||||
inline void chgDouble(vluint32_t* oldp, double newval) {
|
||||
chgDouble(oldp - this->oldp(0), newval);
|
||||
}
|
||||
|
||||
/// Inside dumping routines, dump one signal
|
||||
void fullBit(vluint32_t code, const vluint32_t newval) {
|
||||
// Note the &1, so we don't require clean input -- makes more common no change case faster
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
*m_writep++=('0'+static_cast<char>(newval&1)); printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++=((newval&(1L<<bit))?'1':'0');
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) = newval;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++ = ((newval & (VL_ULL(1) << bit)) ? '1' : '0');
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
||||
m_sigs_oldvalp[code + word] = newval[word];
|
||||
}
|
||||
*m_writep++ = 'b';
|
||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
||||
*m_writep++ = ((newval[(bit / 32)] & (1L << (bit & 0x1f))) ? '1' : '0');
|
||||
}
|
||||
*m_writep ++= ' '; printCode(code); *m_writep ++= '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullArray(vluint32_t code, const vluint64_t* newval, int bits) {
|
||||
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) {
|
||||
m_sigs_oldvalp[code + word] = newval[word];
|
||||
}
|
||||
*m_writep ++= 'b';
|
||||
for (int bit = bits - 1; bit >= 0; --bit) {
|
||||
*m_writep++ = ((newval[(bit / 64)] & (VL_ULL(1) << (bit & 0x3f))) ? '1' : '0');
|
||||
}
|
||||
*m_writep ++= ' '; printCode(code); *m_writep ++= '\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
m_sigs_oldvalp[code+1] = newtri;
|
||||
*m_writep++ = "01zz"[m_sigs_oldvalp[code]
|
||||
| (m_sigs_oldvalp[code+1]<<1)];
|
||||
printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits) {
|
||||
m_sigs_oldvalp[code] = newval;
|
||||
m_sigs_oldvalp[code+1] = newtri;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++ = "01zz"[((newval >> bit)&1)
|
||||
| (((newtri >> bit)&1)<<1)];
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriQuad(vluint32_t code, const vluint64_t newval,
|
||||
const vluint32_t newtri, int bits) {
|
||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) = newval;
|
||||
(*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code+1]))) = newtri;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++ = "01zz"[((newval >> bit) & VL_ULL(1))
|
||||
| (((newtri >> bit) & VL_ULL(1)) << VL_ULL(1))];
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriArray(vluint32_t code, const vluint32_t* newvalp,
|
||||
const vluint32_t* newtrip, int bits) {
|
||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
||||
m_sigs_oldvalp[code+word*2] = newvalp[word];
|
||||
m_sigs_oldvalp[code+word*2+1] = newtrip[word];
|
||||
}
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
vluint32_t valbit = (newvalp[(bit/32)]>>(bit&0x1f)) & 1;
|
||||
vluint32_t tribit = (newtrip[(bit/32)]>>(bit&0x1f)) & 1;
|
||||
*m_writep++ = "01zz"[valbit | (tribit<<1)];
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
/// Inside dumping routines, dump one signal, faster when not inlined
|
||||
/// due to code size reduction.
|
||||
void fullBit(vluint32_t code, const vluint32_t newval);
|
||||
void fullBus(vluint32_t code, const vluint32_t newval, int bits);
|
||||
void fullQuad(vluint32_t code, const vluint64_t newval, int bits);
|
||||
void fullArray(vluint32_t code, const vluint32_t* newvalp, int bits);
|
||||
void fullArray(vluint32_t code, const vluint64_t* newvalp, int bits);
|
||||
void fullTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri);
|
||||
void fullTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri, int bits);
|
||||
void fullTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri, int bits);
|
||||
void fullTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
|
||||
int bits);
|
||||
void fullDouble(vluint32_t code, const double newval);
|
||||
void fullFloat(vluint32_t code, const float newval);
|
||||
|
||||
/// Inside dumping routines, dump one signal as unknowns
|
||||
/// Presently this code doesn't change the oldval vector.
|
||||
/// Thus this is for special standalone applications that after calling
|
||||
/// fullBitX, must when then value goes non-X call fullBit.
|
||||
inline void fullBitX(vluint32_t code) {
|
||||
*m_writep++='x'; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
inline void fullBusX(vluint32_t code, int bits) {
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++='x';
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
inline void fullQuadX(vluint32_t code, int bits) { fullBusX(code, bits); }
|
||||
inline void fullArrayX(vluint32_t code, int bits) { fullBusX(code, bits); }
|
||||
|
||||
/// Inside dumping routines, dump one signal if it has changed
|
||||
/// Inside dumping routines, dump one signal if it has changed.
|
||||
/// We do want to inline these to avoid calls when the value did not change.
|
||||
inline void chgBit(vluint32_t code, const vluint32_t newval) {
|
||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
// Verilator 3.510 and newer provide clean input, so the below
|
||||
// is only for back compatibility
|
||||
if (VL_UNLIKELY(diff & 1)) { // Change after clean?
|
||||
fullBit(code, newval);
|
||||
}
|
||||
}
|
||||
vluint32_t diff = oldp(code)[0] ^ newval;
|
||||
if (VL_UNLIKELY(diff)) fullBit(code, newval);
|
||||
}
|
||||
inline void chgBus(vluint32_t code, const vluint32_t newval, int bits) {
|
||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
||||
vluint32_t diff = oldp(code)[0] ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
|
||||
fullBus(code, newval, bits);
|
||||
@@ -347,33 +240,32 @@ public:
|
||||
}
|
||||
}
|
||||
inline void chgQuad(vluint32_t code, const vluint64_t newval, int bits) {
|
||||
vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) ^ newval;
|
||||
vluint64_t diff = (*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) {
|
||||
if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
|
||||
fullQuad(code, newval, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgArray(vluint32_t code, const vluint32_t* newval, int bits) {
|
||||
inline void chgArray(vluint32_t code, const vluint32_t* newvalp, int bits) {
|
||||
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
||||
if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newval[word])) {
|
||||
fullArray(code, newval, bits);
|
||||
if (VL_UNLIKELY(oldp(code)[word] ^ newvalp[word])) {
|
||||
fullArray(code, newvalp, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgArray(vluint32_t code, const vluint64_t* newval, int bits) {
|
||||
inline void chgArray(vluint32_t code, const vluint64_t* newvalp, int bits) {
|
||||
for (int word = 0; word < (((bits - 1) / 64) + 1); ++word) {
|
||||
if (VL_UNLIKELY(m_sigs_oldvalp[code + word] ^ newval[word])) {
|
||||
fullArray(code, newval, bits);
|
||||
if (VL_UNLIKELY(*(reinterpret_cast<vluint64_t*>(oldp(code + 2 * word)))
|
||||
^ newvalp[word])) {
|
||||
fullArray(code, newvalp, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgTriBit(vluint32_t code, const vluint32_t newval,
|
||||
const vluint32_t newtri) {
|
||||
vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval)
|
||||
| (m_sigs_oldvalp[code+1] ^ newtri));
|
||||
inline void chgTriBit(vluint32_t code, const vluint32_t newval, const vluint32_t newtri) {
|
||||
vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
// Verilator 3.510 and newer provide clean input, so the below
|
||||
// is only for back compatibility
|
||||
@@ -382,54 +274,55 @@ public:
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgTriBus(vluint32_t code, const vluint32_t newval,
|
||||
const vluint32_t newtri, int bits) {
|
||||
vluint32_t diff = ((m_sigs_oldvalp[code] ^ newval)
|
||||
| (m_sigs_oldvalp[code+1] ^ newtri));
|
||||
inline void chgTriBus(vluint32_t code, const vluint32_t newval, const vluint32_t newtri,
|
||||
int bits) {
|
||||
vluint32_t diff = ((oldp(code)[0] ^ newval) | (oldp(code)[1] ^ newtri));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits==32 || (diff & ((1U<<bits)-1) ))) {
|
||||
if (VL_UNLIKELY(bits == 32 || (diff & ((1U << bits) - 1)))) {
|
||||
fullTriBus(code, newval, newtri, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgTriQuad(vluint32_t code, const vluint64_t newval,
|
||||
const vluint32_t newtri, int bits) {
|
||||
vluint64_t diff = ( ((*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code]))) ^ newval)
|
||||
| ((*(reinterpret_cast<vluint64_t*>(&m_sigs_oldvalp[code+1]))) ^ newtri));
|
||||
inline void chgTriQuad(vluint32_t code, const vluint64_t newval, const vluint64_t newtri,
|
||||
int bits) {
|
||||
vluint64_t diff = (((*(reinterpret_cast<vluint64_t*>(oldp(code)))) ^ newval)
|
||||
| ((*(reinterpret_cast<vluint64_t*>(oldp(code + 1)))) ^ newtri));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits == 64 || (diff & ((VL_ULL(1) << bits) - 1)))) {
|
||||
if (VL_UNLIKELY(bits == 64 || (diff & ((1ULL << bits) - 1)))) {
|
||||
fullTriQuad(code, newval, newtri, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp,
|
||||
const vluint32_t* newtrip, int bits) {
|
||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
||||
if (VL_UNLIKELY((m_sigs_oldvalp[code+word*2] ^ newvalp[word])
|
||||
| (m_sigs_oldvalp[code+word*2+1] ^ newtrip[word]))) {
|
||||
fullTriArray(code,newvalp,newtrip,bits);
|
||||
inline void chgTriArray(vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip,
|
||||
int bits) {
|
||||
for (int word = 0; word < (((bits - 1) / 32) + 1); ++word) {
|
||||
if (VL_UNLIKELY((oldp(code)[word * 2] ^ newvalp[word])
|
||||
| (oldp(code)[word * 2 + 1] ^ newtrip[word]))) {
|
||||
fullTriArray(code, newvalp, newtrip, bits);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgDouble(vluint32_t code, const double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY((*(reinterpret_cast<double*>(&m_sigs_oldvalp[code]))) != newval)) {
|
||||
if (VL_UNLIKELY((*(reinterpret_cast<double*>(oldp(code)))) != newval)) {
|
||||
fullDouble(code, newval);
|
||||
}
|
||||
}
|
||||
inline void chgFloat(vluint32_t code, const float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY((*(reinterpret_cast<float*>(&m_sigs_oldvalp[code]))) != newval)) {
|
||||
fullFloat(code, newval);
|
||||
}
|
||||
}
|
||||
|
||||
protected:
|
||||
// METHODS
|
||||
// Old/standalone API only
|
||||
void evcd(bool flag) { m_evcd = flag; }
|
||||
#endif // VL_TRACE_VCD_OLD_API
|
||||
};
|
||||
|
||||
// Declare specializations here they are used in VerilatedVcdC just below
|
||||
template <> void VerilatedTrace<VerilatedVcd>::dump(vluint64_t timeui);
|
||||
template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const char* unitp);
|
||||
template <> void VerilatedTrace<VerilatedVcd>::set_time_unit(const std::string& unit);
|
||||
template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const char* unitp);
|
||||
template <> void VerilatedTrace<VerilatedVcd>::set_time_resolution(const std::string& unit);
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdC
|
||||
/// Create a VCD dump file in C standalone (no SystemC) simulations.
|
||||
@@ -441,12 +334,14 @@ class VerilatedVcdC {
|
||||
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcdC);
|
||||
|
||||
public:
|
||||
explicit VerilatedVcdC(VerilatedVcdFile* filep = NULL)
|
||||
: m_sptrace(filep) {}
|
||||
explicit VerilatedVcdC(VerilatedVcdFile* filep = nullptr)
|
||||
: m_sptrace{filep} {}
|
||||
~VerilatedVcdC() { close(); }
|
||||
/// Routines can only be called from one thread; allow next call from different thread
|
||||
void changeThread() { spTrace()->changeThread(); }
|
||||
|
||||
public:
|
||||
// ACCESSORS
|
||||
/// Is file open?
|
||||
@@ -474,16 +369,25 @@ public:
|
||||
void dump(vluint32_t timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||
void dump(int timestamp) { dump(static_cast<vluint64_t>(timestamp)); }
|
||||
/// Set time units (s/ms, defaults to ns)
|
||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
||||
/// For Verilated models, these propage from the Verilated default --timeunit
|
||||
void set_time_unit(const char* unit) { m_sptrace.set_time_unit(unit); }
|
||||
void set_time_unit(const std::string& unit) { set_time_unit(unit.c_str()); }
|
||||
void set_time_unit(const std::string& unit) { m_sptrace.set_time_unit(unit); }
|
||||
/// Set time resolution (s/ms, defaults to ns)
|
||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
||||
/// For Verilated models, these propage from the Verilated default --timeunit
|
||||
void set_time_resolution(const char* unit) { m_sptrace.set_time_resolution(unit); }
|
||||
void set_time_resolution(const std::string& unit) { set_time_resolution(unit.c_str()); }
|
||||
void set_time_resolution(const std::string& unit) { m_sptrace.set_time_resolution(unit); }
|
||||
|
||||
/// Internal class access
|
||||
inline VerilatedVcd* spTrace() { return &m_sptrace; }
|
||||
|
||||
#ifdef VL_TRACE_VCD_OLD_API
|
||||
//=========================================================================
|
||||
// Note: These are only for testing for backward compatibility with foreign
|
||||
// code and is not used by Verilator. Do not use these as there is no
|
||||
// guarantee of functionality.
|
||||
/// Use evcd format
|
||||
void evcd(bool flag) VL_MT_UNSAFE_ONE { m_sptrace.evcd(flag); }
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
|
||||
@@ -25,18 +25,18 @@
|
||||
//======================================================================
|
||||
|
||||
//--------------------------------------------------
|
||||
#if (SYSTEMC_VERSION>=20050714)
|
||||
// SystemC 2.1.v1
|
||||
// SystemC 2.1.v1
|
||||
// cppcheck-suppress unusedFunction
|
||||
void VerilatedVcdSc::write_comment(const std::string &) {}
|
||||
void VerilatedVcdSc::trace(const unsigned int &, const std::string &, const char**) {}
|
||||
void VerilatedVcdSc::write_comment(const std::string&) {}
|
||||
void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**) {}
|
||||
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const std::string& name ) {}
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const std::string& name, int width ) {}
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace(const tp& object, const std::string& name) {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace(const tp& object, const std::string& name, int width) {}
|
||||
|
||||
#if (SYSTEMC_VERSION>=20171012)
|
||||
// clang-format off
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
#endif
|
||||
@@ -73,88 +73,7 @@ void VerilatedVcdSc::trace(const unsigned int &, const std::string &, const char
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
#elif (SYSTEMC_VERSION>20011000)
|
||||
// SystemC 2.0.1
|
||||
// cppcheck-suppress unusedFunction
|
||||
void VerilatedVcdSc::write_comment(const sc_string &) {}
|
||||
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
|
||||
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( 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
|
||||
#if (SYSTEMC_VERSION>20041000)
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
DECL_TRACE_METHOD_B( 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_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
||||
DECL_TRACE_METHOD_A( sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
#else
|
||||
// SystemC 1.2.1beta
|
||||
// cppcheck-suppress unusedFunction
|
||||
void VerilatedVcdSc::write_comment(const sc_string &) {}
|
||||
void VerilatedVcdSc::trace(const unsigned int&, const sc_string&, const char**) {}
|
||||
|
||||
#define DECL_TRACE_METHOD_A(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name ) {}
|
||||
#define DECL_TRACE_METHOD_B(tp) \
|
||||
void VerilatedVcdSc::trace( const tp& object, const sc_string& name, int width ) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( short unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( long unsigned int )
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short int )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long int )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_A( sc_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
||||
#endif
|
||||
// clang-format on
|
||||
|
||||
#undef DECL_TRACE_METHOD_A
|
||||
#undef DECL_TRACE_METHOD_B
|
||||
|
||||
+15
-114
@@ -31,44 +31,29 @@
|
||||
/// This class is passed to the SystemC simulation kernel, just like a
|
||||
/// documented SystemC trace format.
|
||||
|
||||
class VerilatedVcdSc
|
||||
: sc_trace_file
|
||||
, public VerilatedVcdC
|
||||
{
|
||||
class VerilatedVcdSc : sc_trace_file, public VerilatedVcdC {
|
||||
// CONSTRUCTORS
|
||||
VL_UNCOPYABLE(VerilatedVcdSc);
|
||||
|
||||
public:
|
||||
VerilatedVcdSc() {
|
||||
sc_get_curr_simcontext()->add_trace_file(this);
|
||||
# if (SYSTEMC_VERSION>=20060505)
|
||||
// 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.
|
||||
sc_time t1sec(1,SC_SEC);
|
||||
if (t1sec.to_default_time_units()!=0) {
|
||||
sc_time tunits(1.0/t1sec.to_default_time_units(),SC_SEC);
|
||||
sc_time t1sec(1, SC_SEC);
|
||||
if (t1sec.to_default_time_units() != 0) {
|
||||
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());
|
||||
# elif (SYSTEMC_VERSION>20011000)
|
||||
// To confuse matters 2.1.beta returns a char* here, while 2.1.v1 returns a std::string
|
||||
// we allow both flavors with overloaded set_time_* functions.
|
||||
spTrace()->set_time_unit(sc_get_default_time_unit().to_string());
|
||||
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
|
||||
# endif
|
||||
}
|
||||
virtual ~VerilatedVcdSc() { close(); }
|
||||
|
||||
// METHODS
|
||||
/// Called by SystemC simulate()
|
||||
virtual void cycle(bool delta_cycle) {
|
||||
# if (SYSTEMC_VERSION>20011000)
|
||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||
# else
|
||||
// VCD files must have integer timestamps, so we write all times in
|
||||
// increments of time_resolution
|
||||
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
|
||||
# endif
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -78,23 +63,20 @@ private:
|
||||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
virtual void set_time_unit(int exponent10_seconds) {} // deprecated
|
||||
#endif
|
||||
#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION>=20111100)
|
||||
virtual void set_time_unit(double v, sc_time_unit tu) {}
|
||||
#endif
|
||||
|
||||
virtual void set_time_unit(double v, sc_time_unit tu) {} // LCOV_EXCL_LINE
|
||||
|
||||
//--------------------------------------------------
|
||||
# if (SYSTEMC_VERSION>=20050714)
|
||||
// SystemC 2.1.v1
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
virtual void trace(const tp& object, const std::string& name);
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
// SystemC 2.1.v1
|
||||
#define DECL_TRACE_METHOD_A(tp) virtual void trace(const tp& object, const std::string& name);
|
||||
#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**);
|
||||
|
||||
#if (SYSTEMC_VERSION>=20171012)
|
||||
// clang-format off
|
||||
// Formatting matches that of sc_trace.h
|
||||
#if (SYSTEMC_VERSION >= 20171012)
|
||||
DECL_TRACE_METHOD_A( sc_event )
|
||||
DECL_TRACE_METHOD_A( sc_time )
|
||||
#endif
|
||||
@@ -131,91 +113,10 @@ private:
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
// clang-format on
|
||||
|
||||
//--------------------------------------------------
|
||||
# elif (SYSTEMC_VERSION>20011000)
|
||||
// SystemC 2.0.1
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
virtual void trace(const tp& object, const sc_string& name);
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace(const tp& object, const sc_string& name, int width);
|
||||
|
||||
virtual void write_comment(const sc_string&);
|
||||
virtual void trace(const unsigned int&, const sc_string&, const char**);
|
||||
virtual void delta_cycles(bool) {}
|
||||
virtual void space(int n) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( 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
|
||||
#if (SYSTEMC_VERSION>20041000)
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
DECL_TRACE_METHOD_B( 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_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_fxnum_fast )
|
||||
DECL_TRACE_METHOD_A( sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
# else
|
||||
// SystemC 1.2.1beta
|
||||
# define DECL_TRACE_METHOD_A(tp) \
|
||||
virtual void trace(const tp& object, const sc_string& name);
|
||||
# define DECL_TRACE_METHOD_B(tp) \
|
||||
virtual void trace(const tp& object, const sc_string& name, int width);
|
||||
|
||||
virtual void write_comment(const sc_string&);
|
||||
virtual void trace(const unsigned int&, const sc_string&, const char**);
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( short unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( long unsigned int )
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short int )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long int )
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_logic )
|
||||
DECL_TRACE_METHOD_A( sc_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_bool_vector )
|
||||
DECL_TRACE_METHOD_A( sc_signal_logic_vector )
|
||||
DECL_TRACE_METHOD_A( sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_unsigned )
|
||||
DECL_TRACE_METHOD_A( sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved )
|
||||
DECL_TRACE_METHOD_A( sc_signal_resolved_vector )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_bv_ns::sc_lv_base )
|
||||
# endif
|
||||
|
||||
# undef DECL_TRACE_METHOD_A
|
||||
# undef DECL_TRACE_METHOD_B
|
||||
#undef DECL_TRACE_METHOD_A
|
||||
#undef DECL_TRACE_METHOD_B
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+776
-795
File diff suppressed because it is too large
Load Diff
+175
-152
@@ -22,145 +22,145 @@
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATEDOS_H_
|
||||
#define _VERILATEDOS_H_ 1 ///< Header Guard
|
||||
|
||||
// Current clang-format versions botch #ifdef inclusion, so
|
||||
// clang-format off
|
||||
//=========================================================================
|
||||
// Compiler pragma abstraction
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
|
||||
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
|
||||
# define VL_ATTR_COLD __attribute__ ((cold))
|
||||
# define VL_ATTR_HOT __attribute__ ((hot))
|
||||
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, (fmtArgNum), (fmtArgNum)+1)))
|
||||
# define VL_ATTR_PURE __attribute__ ((pure))
|
||||
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
||||
# define VL_FUNC __func__
|
||||
# define VL_ATTR_ALIGNED(alignment) __attribute__((aligned(alignment)))
|
||||
# define VL_ATTR_ALWINLINE __attribute__((always_inline))
|
||||
# define VL_ATTR_COLD __attribute__((cold))
|
||||
# define VL_ATTR_HOT __attribute__((hot))
|
||||
# define VL_ATTR_NORETURN __attribute__((noreturn))
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__((format(printf, (fmtArgNum), (fmtArgNum) + 1)))
|
||||
# define VL_ATTR_PURE __attribute__((pure))
|
||||
# define VL_ATTR_UNUSED __attribute__((unused))
|
||||
# define VL_FUNC __func__
|
||||
# if defined(__clang__) && defined(VL_THREADED)
|
||||
# define VL_ACQUIRE(...) __attribute__ ((acquire_capability(__VA_ARGS__)))
|
||||
# define VL_ACQUIRE_SHARED(...) __attribute__ ((acquire_shared_capability(__VA_ARGS__)))
|
||||
# define VL_RELEASE(...) __attribute__ ((release_capability(__VA_ARGS__)))
|
||||
# define VL_RELEASE_SHARED(...) __attribute__ ((release_shared_capability(__VA_ARGS__)))
|
||||
# define VL_TRY_ACQUIRE(...) __attribute__ ((try_acquire_capability(__VA_ARGS__)))
|
||||
# define VL_TRY_ACQUIRE_SHARED(...) __attribute__ ((try_acquire_shared_capability(__VA_ARGS__)))
|
||||
# define VL_CAPABILITY(x) __attribute__ ((capability(x)))
|
||||
# define VL_REQUIRES(x) __attribute__ ((requires_capability(x)))
|
||||
# define VL_GUARDED_BY(x) __attribute__ ((guarded_by(x)))
|
||||
# define VL_EXCLUDES(x) __attribute__ ((locks_excluded(x)))
|
||||
# define VL_SCOPED_CAPABILITY __attribute__ ((scoped_lockable))
|
||||
# define VL_ACQUIRE(...) __attribute__((acquire_capability(__VA_ARGS__)))
|
||||
# define VL_ACQUIRE_SHARED(...) __attribute__((acquire_shared_capability(__VA_ARGS__)))
|
||||
# define VL_RELEASE(...) __attribute__((release_capability(__VA_ARGS__)))
|
||||
# define VL_RELEASE_SHARED(...) __attribute__((release_shared_capability(__VA_ARGS__)))
|
||||
# define VL_TRY_ACQUIRE(...) __attribute__((try_acquire_capability(__VA_ARGS__)))
|
||||
# define VL_TRY_ACQUIRE_SHARED(...) __attribute__((try_acquire_shared_capability(__VA_ARGS__)))
|
||||
# define VL_CAPABILITY(x) __attribute__((capability(x)))
|
||||
# define VL_REQUIRES(x) __attribute__((requires_capability(x)))
|
||||
# define VL_GUARDED_BY(x) __attribute__((guarded_by(x)))
|
||||
# define VL_EXCLUDES(x) __attribute__((locks_excluded(x)))
|
||||
# define VL_SCOPED_CAPABILITY __attribute__((scoped_lockable))
|
||||
# endif
|
||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define VL_LIKELY(x) __builtin_expect(!!(x), 1)
|
||||
# define VL_UNLIKELY(x) __builtin_expect(!!(x), 0)
|
||||
# define VL_UNREACHABLE __builtin_unreachable();
|
||||
# define VL_PREFETCH_RD(p) __builtin_prefetch((p),0)
|
||||
# define VL_PREFETCH_RW(p) __builtin_prefetch((p),1)
|
||||
# define VL_PREFETCH_RD(p) __builtin_prefetch((p), 0)
|
||||
# define VL_PREFETCH_RW(p) __builtin_prefetch((p), 1)
|
||||
#elif defined(_MSC_VER)
|
||||
# define VL_FUNC __FUNCTION__
|
||||
# define VL_FUNC __FUNCTION__
|
||||
#endif
|
||||
|
||||
// Defaults for unsupported compiler features
|
||||
#ifndef VL_ATTR_ALIGNED
|
||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||
#endif
|
||||
#ifndef VL_ATTR_ALWINLINE
|
||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||
#endif
|
||||
#ifndef VL_ATTR_COLD
|
||||
# define VL_ATTR_COLD ///< Function is rarely executed
|
||||
# define VL_ATTR_COLD ///< Function is rarely executed
|
||||
#endif
|
||||
#ifndef VL_ATTR_HOT
|
||||
# define VL_ATTR_HOT ///< Function is highly executed
|
||||
# define VL_ATTR_HOT ///< Function is highly executed
|
||||
#endif
|
||||
#ifndef VL_ATTR_NORETURN
|
||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||
#endif
|
||||
#ifndef VL_ATTR_PRINTF
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
#endif
|
||||
#ifndef VL_ATTR_PURE
|
||||
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
||||
# define VL_ATTR_PURE ///< Function is pure (and thus also VL_MT_SAFE)
|
||||
#endif
|
||||
#ifndef VL_ATTR_UNUSED
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
#endif
|
||||
#ifndef VL_FUNC
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
#endif
|
||||
#ifndef VL_CAPABILITY
|
||||
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
||||
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired a shared capability (-fthread-safety)
|
||||
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
||||
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
||||
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
||||
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
||||
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
||||
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
|
||||
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
|
||||
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
|
||||
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired shared (-fthread-safety)
|
||||
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
|
||||
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
|
||||
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
|
||||
# define VL_GUARDED_BY(x) ///< Name of mutex protecting this variable (-fthread-safety)
|
||||
# define VL_SCOPED_CAPABILITY ///< Scoped threaded capability/lock (-fthread-safety)
|
||||
#endif
|
||||
#ifndef VL_LIKELY
|
||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||
# define VL_LIKELY(x) (!!(x)) ///< Boolean expression more often true than false
|
||||
# define VL_UNLIKELY(x) (!!(x)) ///< Boolean expression more often false than true
|
||||
#endif
|
||||
#define VL_UNCOVERABLE(x) VL_UNLIKELY(x) ///< Boolean expression never hit by users (no coverage)
|
||||
# define VL_UNCOVERABLE(x) VL_UNLIKELY(x) ///< Boolean expression never hit by users (no coverage)
|
||||
#ifndef VL_UNREACHABLE
|
||||
# define VL_UNREACHABLE ///< Point that may never be reached
|
||||
# define VL_UNREACHABLE ///< Point that may never be reached
|
||||
#endif
|
||||
#ifndef VL_PREFETCH_RD
|
||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||
#endif
|
||||
#ifndef VL_PREFETCH_RW
|
||||
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
||||
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
||||
#endif
|
||||
|
||||
#ifdef VL_THREADED
|
||||
# if defined(_MSC_VER) && _MSC_VER >= 1900
|
||||
# define VL_THREAD_LOCAL thread_local
|
||||
# elif defined(__GNUC__)
|
||||
# if (__cplusplus < 201103L) && !defined(VL_THREADED_NO_C11_WARNING)
|
||||
# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler"
|
||||
# if (__cplusplus < 201103L)
|
||||
# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler"
|
||||
# endif
|
||||
# else
|
||||
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
|
||||
# endif
|
||||
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
||||
# define VL_THREAD_LOCAL thread_local ///< Use new C++ static local thread
|
||||
#else
|
||||
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
||||
# define VL_THREAD_LOCAL ///< Use new C++ static local thread
|
||||
#endif
|
||||
#define VL_THREAD ///< Deprecated
|
||||
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||
|
||||
#define VL_THREAD ///< Deprecated
|
||||
#define VL_STATIC_OR_THREAD static ///< Deprecated
|
||||
|
||||
#define VL_PURE ///< Comment tag that Function is pure (and thus also VL_MT_SAFE)
|
||||
#define VL_MT_SAFE ///< Comment tag that function is threadsafe when VL_THREADED
|
||||
#define VL_MT_SAFE_POSTINIT ///< Comment tag that function is threadsafe when VL_THREADED, only during normal operation (post-init)
|
||||
#define VL_MT_SAFE_POSTINIT ///< Comment tag that function is threadsafe when VL_THREADED, only
|
||||
///< during normal operation (post-init)
|
||||
#define VL_MT_UNSAFE ///< Comment tag that function is not threadsafe when VL_THREADED
|
||||
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED, protected to make sure single-caller
|
||||
#define VL_MT_UNSAFE_ONE ///< Comment tag that function is not threadsafe when VL_THREADED,
|
||||
///< protected to make sure single-caller
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define VL_ULL(c) (c##ui64) ///< Add appropriate suffix to 64-bit constant
|
||||
#else
|
||||
# define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant
|
||||
#endif
|
||||
#define VL_ULL(c) (c##ULL) ///< Add appropriate suffix to 64-bit constant (deprecated)
|
||||
|
||||
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
||||
#define VL_UL(c) (static_cast<IData>(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
|
||||
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
|
||||
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__) || __cplusplus < 201103L
|
||||
# define VL_DANGLING(var)
|
||||
#else
|
||||
///< After e.g. delete, set variable to NULL to indicate must not use later
|
||||
/// After e.g. delete, set variable to nullptr to indicate must not use later
|
||||
# define VL_DANGLING(var) \
|
||||
do { \
|
||||
(var) = NULL; \
|
||||
*const_cast<const void**>(reinterpret_cast<const void* const*>(&var)) = nullptr; \
|
||||
} while (false)
|
||||
#endif
|
||||
|
||||
///< Perform an e.g. delete, then set variable to NULL to indicate must not use later.
|
||||
///< Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
|
||||
/// Perform an e.g. delete, then set variable to nullptr to indicate must not use later.
|
||||
/// Unlike VL_DO_CLEAR the setting of the variable is only for debug reasons.
|
||||
#define VL_DO_DANGLING(stmt, var) \
|
||||
do { \
|
||||
do { \
|
||||
@@ -169,7 +169,7 @@
|
||||
VL_DANGLING(var); \
|
||||
} while (false)
|
||||
|
||||
///< Perform an e.g. delete, then set variable to NULL as a requirement
|
||||
/// Perform an e.g. delete, then set variable to nullptr as a requirement
|
||||
#define VL_DO_CLEAR(stmt, stmt2) \
|
||||
do { \
|
||||
do { \
|
||||
@@ -184,28 +184,18 @@
|
||||
// C++-2011
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(VL_CPPCHECK)
|
||||
// These are deprecated historical defines. We leave them in case users referenced them.
|
||||
# define VL_EQ_DELETE = delete
|
||||
# define vl_unique_ptr std::unique_ptr
|
||||
// By default we use std:: types in C++11.
|
||||
// Define VL_USE_UNORDERED_TYPES to test these pre-C++11 classes
|
||||
# ifdef VL_USE_UNORDERED_TYPES
|
||||
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
|
||||
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
|
||||
# else
|
||||
# define vl_unordered_map std::unordered_map
|
||||
# define vl_unordered_set std::unordered_set
|
||||
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||
# endif
|
||||
# define vl_unordered_map std::unordered_map
|
||||
# define vl_unordered_set std::unordered_set
|
||||
# define VL_INCLUDE_UNORDERED_MAP <unordered_map>
|
||||
# define VL_INCLUDE_UNORDERED_SET <unordered_set>
|
||||
# define VL_FINAL final
|
||||
# define VL_MUTABLE mutable
|
||||
# define VL_OVERRIDE override
|
||||
#else
|
||||
# define VL_EQ_DELETE
|
||||
# define vl_unique_ptr std::auto_ptr
|
||||
# define VL_INCLUDE_UNORDERED_MAP "verilated_unordered_set_map.h"
|
||||
# define VL_INCLUDE_UNORDERED_SET "verilated_unordered_set_map.h"
|
||||
# define VL_FINAL
|
||||
# define VL_OVERRIDE
|
||||
# error "Verilator requires a C++11 or newer compiler"
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
@@ -215,6 +205,20 @@
|
||||
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Internal coverage
|
||||
|
||||
#ifdef VL_GCOV
|
||||
extern "C" {
|
||||
void __gcov_flush(); // gcc sources gcc/gcov-io.h has the prototype
|
||||
}
|
||||
/// Flush internal code coverage data before e.g. abort()
|
||||
# define VL_GCOV_FLUSH() \
|
||||
__gcov_flush()
|
||||
#else
|
||||
# define VL_GCOV_FLUSH()
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Warning disabled
|
||||
|
||||
@@ -247,47 +251,47 @@
|
||||
# include <stdint.h>
|
||||
# include <sys/types.h> // __WORDSIZE
|
||||
# include <unistd.h> // ssize_t
|
||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef char vlsint8_t; ///< 8-bit signed type
|
||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||
typedef short int vlsint16_t; ///< 16-bit signed type
|
||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef char vlsint8_t; ///< 8-bit signed type
|
||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||
typedef short int vlsint16_t; ///< 16-bit signed type
|
||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||
# if defined(__uint32_t_defined) || defined(___int32_t_defined) // Newer Cygwin uint32_t in stdint.h as an unsigned int
|
||||
typedef int32_t vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||
typedef int32_t vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||
# else // Older Cygwin has long==uint32_t
|
||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef long vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef long vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned long vluint32_t; ///< 32-bit unsigned type
|
||||
# endif
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
# else
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# endif
|
||||
|
||||
#elif defined(_WIN32) && defined(_MSC_VER)
|
||||
|
||||
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef signed __int8 vlsint8_t; ///< 8-bit signed type
|
||||
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
||||
typedef signed __int16 vlsint16_t; ///< 16-bit signed type
|
||||
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
||||
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
||||
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||
typedef unsigned __int8 uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int16 uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned __int32 uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef signed __int8 vlsint8_t; ///< 8-bit signed type
|
||||
typedef unsigned __int8 vluint8_t; ///< 8-bit unsigned type
|
||||
typedef signed __int16 vlsint16_t; ///< 16-bit signed type
|
||||
typedef unsigned __int16 vluint16_t; ///< 16-bit unsigned type
|
||||
typedef signed __int32 vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned __int32 vluint32_t; ///< 32-bit unsigned type
|
||||
typedef signed __int64 vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned __int64 vluint64_t; ///< 64-bit unsigned type
|
||||
|
||||
# ifndef _SSIZE_T_DEFINED
|
||||
# ifdef _WIN64
|
||||
typedef signed __int64 ssize_t; ///< signed size_t; returned from read()
|
||||
# ifdef _WIN64
|
||||
typedef signed __int64 ssize_t; ///< signed size_t; returned from read()
|
||||
# else
|
||||
typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
|
||||
typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
|
||||
# endif
|
||||
# endif
|
||||
|
||||
@@ -297,18 +301,18 @@ typedef signed __int32 ssize_t; ///< signed size_t; returned fro
|
||||
# include <stdint.h> // Linux and most flavors
|
||||
# include <sys/types.h> // __WORDSIZE
|
||||
# include <unistd.h> // ssize_t
|
||||
typedef char vlsint8_t; ///< 8-bit signed type
|
||||
typedef uint8_t vluint8_t; ///< 8-bit unsigned type
|
||||
typedef short vlsint16_t; ///< 16-bit signed type
|
||||
typedef uint16_t vluint16_t; ///< 16-bit unsigned type
|
||||
typedef int vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||
typedef char vlsint8_t; ///< 8-bit signed type
|
||||
typedef uint8_t vluint8_t; ///< 8-bit unsigned type
|
||||
typedef short vlsint16_t; ///< 16-bit signed type
|
||||
typedef uint16_t vluint16_t; ///< 16-bit unsigned type
|
||||
typedef int vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit unsigned type
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long vluint64_t; ///< 64-bit unsigned type
|
||||
# else
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
typedef long long vlsint64_t; ///< 64-bit signed type
|
||||
typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# endif
|
||||
#endif
|
||||
|
||||
@@ -351,14 +355,14 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
//=========================================================================
|
||||
// Integer size macros
|
||||
|
||||
#define VL_BYTESIZE 8 ///< Bits in a CData / byte
|
||||
#define VL_SHORTSIZE 16 ///< Bits in a SData / short
|
||||
#define VL_IDATASIZE 32 ///< Bits in a IData / word
|
||||
#define VL_WORDSIZE IDATASIZE ///< Legacy define
|
||||
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
|
||||
#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry)
|
||||
#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE)
|
||||
#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment)
|
||||
#define VL_BYTESIZE 8 ///< Bits in a CData / byte
|
||||
#define VL_SHORTSIZE 16 ///< Bits in a SData / short
|
||||
#define VL_IDATASIZE 32 ///< Bits in a IData / word
|
||||
#define VL_WORDSIZE VL_IDATASIZE ///< Legacy define
|
||||
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
|
||||
#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry)
|
||||
#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE)
|
||||
#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment)
|
||||
|
||||
/// Bytes this number of bits needs (1 bit=1 byte)
|
||||
#define VL_BYTES_I(nbits) (((nbits) + (VL_BYTESIZE - 1)) / VL_BYTESIZE)
|
||||
@@ -371,15 +375,15 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
// Class definition helpers
|
||||
|
||||
// Used to declare a class as uncopyable; put after a private:
|
||||
#define VL_UNCOPYABLE(Type) \
|
||||
Type(const Type& other) VL_EQ_DELETE; \
|
||||
Type& operator= (const Type&) VL_EQ_DELETE
|
||||
#define VL_UNCOPYABLE(Type) \
|
||||
Type(const Type& other) = delete; \
|
||||
Type& operator=(const Type&) = delete
|
||||
|
||||
//=========================================================================
|
||||
// Verilated function size macros
|
||||
|
||||
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
|
||||
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||
#define VL_MULS_MAX_WORDS 16 ///< Max size in words of MULS operation
|
||||
#define VL_TO_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||
|
||||
//=========================================================================
|
||||
// Base macros
|
||||
@@ -389,11 +393,10 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
#define VL_SIZEBITS_E (VL_EDATASIZE - 1) ///< Bit mask for bits in a quad
|
||||
|
||||
/// Mask for words with 1's where relevant bits are (0=all bits)
|
||||
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) \
|
||||
? ((1U << ((nbits) & VL_SIZEBITS_I) )-1) : ~0)
|
||||
#define VL_MASK_I(nbits) (((nbits) & VL_SIZEBITS_I) ? ((1U << ((nbits) & VL_SIZEBITS_I)) - 1) : ~0)
|
||||
/// Mask for quads with 1's where relevant bits are (0=all bits)
|
||||
#define VL_MASK_Q(nbits) (((nbits) & VL_SIZEBITS_Q) \
|
||||
? ((VL_ULL(1) << ((nbits) & VL_SIZEBITS_Q) )-VL_ULL(1)) : VL_ULL(~0))
|
||||
#define VL_MASK_Q(nbits) \
|
||||
(((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL)
|
||||
/// Mask for EData with 1's where relevant bits are (0=all bits)
|
||||
#define VL_MASK_E(nbits) VL_MASK_I(nbits)
|
||||
#define VL_EUL(n) VL_UL(n) ///< Make constant number EData sized
|
||||
@@ -409,8 +412,8 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
// #defines, to avoid requiring math.h on all compile runs
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# define VL_TRUNC(n) (((n)<0) ? ceil((n)) : floor((n)))
|
||||
# define VL_ROUND(n) (((n)<0) ? ceil((n)-0.5) : floor((n)+0.5))
|
||||
# define VL_TRUNC(n) (((n) < 0) ? ceil((n)) : floor((n)))
|
||||
# define VL_ROUND(n) (((n) < 0) ? ceil((n)-0.5) : floor((n) + 0.5))
|
||||
#else
|
||||
# define VL_TRUNC(n) trunc(n)
|
||||
# define VL_ROUND(n) round(n)
|
||||
@@ -420,15 +423,16 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
// Performance counters
|
||||
|
||||
/// The vluint64_t argument is loaded with a high-performance counter for profiling
|
||||
/// or 0x0 if not implemeted on this platform
|
||||
/// or 0x0 if not implemented on this platform
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
# define VL_RDTSC(val) { \
|
||||
vluint32_t hi, lo; \
|
||||
asm volatile("rdtsc" : "=a" (lo), "=d" (hi)); \
|
||||
(val) = ((vluint64_t)lo) | (((vluint64_t)hi)<<32); \
|
||||
}
|
||||
#define VL_RDTSC(val) \
|
||||
{ \
|
||||
vluint32_t hi, lo; \
|
||||
asm volatile("rdtsc" : "=a"(lo), "=d"(hi)); \
|
||||
(val) = ((vluint64_t)lo) | (((vluint64_t)hi) << 32); \
|
||||
}
|
||||
#elif defined(__aarch64__)
|
||||
# define VL_RDTSC(val) asm volatile("mrs %[rt],PMCCNTR_EL0" : [rt] "=r" (val));
|
||||
# define VL_RDTSC(val) asm volatile("mrs %[rt],PMCCNTR_EL0" : [rt] "=r"(val));
|
||||
#else
|
||||
// We just silently ignore unknown OSes, as only leads to missing statistics
|
||||
# define VL_RDTSC(val) (val) = 0;
|
||||
@@ -467,12 +471,31 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# define VL_STRCASECMP strcasecmp
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Macros controlling target specific optimizations
|
||||
|
||||
// Define VL_PORTABLE_ONLY to disable all target specific optimizations
|
||||
#ifndef VL_PORTABLE_ONLY
|
||||
# ifdef __x86_64__
|
||||
# define VL_X86_64 1
|
||||
# endif
|
||||
#endif // VL_PORTABLE_ONLY
|
||||
// clang-format on
|
||||
|
||||
//=========================================================================
|
||||
// Stringify macros
|
||||
|
||||
#define VL_STRINGIFY(x) VL_STRINGIFY2(x)
|
||||
#define VL_STRINGIFY2(x) #x
|
||||
|
||||
//=========================================================================
|
||||
// Conversions
|
||||
|
||||
namespace vlstd {
|
||||
// C++17's std::as_const
|
||||
template <class T> T const& as_const(T& v) { return v; }
|
||||
}; // namespace vlstd
|
||||
|
||||
//=========================================================================
|
||||
|
||||
#endif // Guard
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2007-2020 by Wilson Snyder. This program is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
#
|
||||
######################################################################
|
||||
|
||||
# DESCRIPTION: Debugging of bison output
|
||||
|
||||
use warnings;
|
||||
use strict;
|
||||
|
||||
my $Debug;
|
||||
|
||||
my %declared;
|
||||
my %used;
|
||||
|
||||
my $body = 0;
|
||||
my $rule = "";
|
||||
my $lineno = 0;
|
||||
foreach my $line (<STDIN>) {
|
||||
$lineno++;
|
||||
chomp $line;
|
||||
$line =~ s!//.*$!!g;
|
||||
$line =~ s!\s+! !g;
|
||||
next if $line eq '';
|
||||
if ($line =~ m!^\%\%!) {
|
||||
$body++;
|
||||
} elsif ($body == 1) {
|
||||
$rule .= $line;
|
||||
if ($line =~ m!^\s*;\s*$!) {
|
||||
#print "Rule: $rule\n";
|
||||
($rule =~ /^([a-zA-Z0-9_]+)(<\S+>)?:(.*)$/) or die "%Error: No rule name: $1\n";
|
||||
my $rulename = $1; my $preaction = $3;
|
||||
$declared{$rulename} = $lineno;
|
||||
$preaction =~ s/\{[^\}]*\}/ /g;
|
||||
#print "RULEN $rulename PA $preaction\n" if $Debug;
|
||||
$rule = '';
|
||||
foreach my $ref (split /\s+/, $preaction) {
|
||||
next if $ref !~ /^[a-zA-Z]/;
|
||||
next if $ref eq $rulename;
|
||||
if (!$used{$ref} && $declared{$ref}) {
|
||||
print " %Warning: $lineno: $ref used by $rulename after declaration\n";
|
||||
}
|
||||
$used{$ref} = $lineno;
|
||||
print " ref $ref\n" if $Debug;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# compile-command: "./bisonreader < ../src/verilog.y"
|
||||
# End:
|
||||
+302
-57
@@ -6,30 +6,71 @@ use warnings;
|
||||
use Cwd;
|
||||
use File::Copy qw(cp);
|
||||
use File::Path qw(mkpath);
|
||||
use File::Spec;
|
||||
use FindBin qw($RealBin);
|
||||
use Getopt::Long;
|
||||
use Parallel::Forker;
|
||||
use Unix::Processors;
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw($Debug);
|
||||
|
||||
our $Opt_Stop = 1;
|
||||
our $Opt_Fastcov = 1;
|
||||
our $Exclude_Branch_Regexp;
|
||||
our $Exclude_Line_Regexp;
|
||||
our $Remove_Gcda_Regexp;
|
||||
|
||||
our @Remove_Sources;
|
||||
our @Source_Globs;
|
||||
|
||||
our $Fork = new Parallel::Forker(use_sig_child => 1, poll_interval => 10*1000);
|
||||
$Fork->max_proc(Unix::Processors->new->max_online * 1.5);
|
||||
$SIG{CHLD} = sub { Parallel::Forker::sig_child($Fork); };
|
||||
$SIG{TERM} = sub { $Fork->kill_tree_all('TERM') if $Fork && $Fork->in_parent; die "Quitting...\n"; };
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
our $Opt_Stage = 0;
|
||||
our $Opt_Hashset;
|
||||
our $opt_stages = '';
|
||||
our $Opt_Scenarios;
|
||||
our %Opt_Stages;
|
||||
our @Opt_Tests;
|
||||
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config("no_auto_abbrev");
|
||||
if (! GetOptions(
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"hashset=s" => \$Opt_Hashset, # driver.pl hashset
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||
"stage=i" => \$Opt_Stage,
|
||||
"fastcov!" => \$Opt_Fastcov, # use fastcov, not documented, for debug
|
||||
"scenarios=s" => \$Opt_Scenarios, # driver.pl scenarios
|
||||
"stage=s" => \$opt_stages, # starting stage number
|
||||
"stages=s" => \$opt_stages, # starting stage number
|
||||
"stop!" => \$Opt_Stop, # stop/do not stop on error in tests
|
||||
"test=s@" => \@Opt_Tests, # test name
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'install_test --help'\n";
|
||||
die "%Error: Bad usage, try 'code_coverage --help'\n";
|
||||
}
|
||||
|
||||
{
|
||||
my $start = 0;
|
||||
my $end = 99;
|
||||
if ($opt_stages && $opt_stages =~ /^(\d+)$/) {
|
||||
$start = $end = $1;
|
||||
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-(\d+$)$/) {
|
||||
$start = $1; $end = $2;
|
||||
} elsif ($opt_stages && $opt_stages =~ /^-(\d+$)$/) {
|
||||
$end = $1;
|
||||
} elsif ($opt_stages && $opt_stages =~ /^(\d+)-$/) {
|
||||
$start = $1;
|
||||
} elsif ($opt_stages) {
|
||||
die "%Error: --stages not understood: $opt_stages,";
|
||||
}
|
||||
for (my $n = $start; $n <= $end; ++$n) { $Opt_Stages{$n} = 1; }
|
||||
}
|
||||
|
||||
test();
|
||||
@@ -41,97 +82,238 @@ sub test {
|
||||
-r "nodist/code_coverage.dat" or die "%Error: Run from the top of the verilator kit,";
|
||||
require "./nodist/code_coverage.dat";
|
||||
|
||||
if ($Opt_Stage <= 0) {
|
||||
print "Stage 0: configure (coverage on)\n";
|
||||
run("make distclean");
|
||||
run("./configure --enable-longtests CXX='g++ --coverage'");
|
||||
run("make -k");
|
||||
if ($Opt_Stages{1}) {
|
||||
travis_fold_start("configure");
|
||||
print "Stage 1: configure (coverage on)\n";
|
||||
run("make distclean || true");
|
||||
run("autoconf");
|
||||
# Exceptions can pollute the branch coverage data
|
||||
run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'");
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{2}) {
|
||||
travis_fold_start("build");
|
||||
print "Stage 2: build\n";
|
||||
my $nproc = Unix::Processors->new->max_online;
|
||||
run("make -k -j $nproc VERILATOR_NO_OPT_BUILD=1");
|
||||
# The optimized versions will not collect good coverage, overwrite them
|
||||
run("cp bin/verilator_bin_dbg bin/verilator_bin");
|
||||
run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin");
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stage <= 1) {
|
||||
print "Stage 1: make examples (with coverage on)\n";
|
||||
run("make examples");
|
||||
run("make test_regress");
|
||||
if ($Opt_Stages{3}) {
|
||||
travis_fold_start("test");
|
||||
print "Stage 3: make tests (with coverage on)\n";
|
||||
if ($#Opt_Tests < 0) {
|
||||
run("make examples VERILATOR_NO_OPT_BUILD=1")
|
||||
if !$Opt_Scenarios || $Opt_Scenarios =~ /dist/i;
|
||||
run("make test_regress VERILATOR_NO_OPT_BUILD=1"
|
||||
. ($Opt_Scenarios ? " SCENARIOS='".$Opt_Scenarios."'" : "")
|
||||
. ($Opt_Hashset ? " DRIVER_HASHSET='--hashset=".$Opt_Hashset."'" : "")
|
||||
. ($Opt_Stop ? '' : ' || true'));
|
||||
} else {
|
||||
foreach my $test (@Opt_Tests) {
|
||||
if (! -f $test && -f "test_regress/t/${test}") {
|
||||
$test = "test_regress/t/${test}";
|
||||
}
|
||||
run($test);
|
||||
}
|
||||
}
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
my $cc_dir = "nodist/obj_dir/coverage";
|
||||
if ($Opt_Stage <= 2) {
|
||||
print "Stage 2: Create info files under $cc_dir\n";
|
||||
if ($Opt_Stages{4}) {
|
||||
travis_fold_start("gcno");
|
||||
print "Stage 4: Create gcno files under $cc_dir\n";
|
||||
mkpath($cc_dir);
|
||||
mkpath("$cc_dir/info");
|
||||
my $dats = `find . -print | grep .gcda`;
|
||||
my %dats;
|
||||
foreach my $dat (split '\n', $dats) {
|
||||
$dats{$dat} = 1;
|
||||
}
|
||||
foreach my $dat (sort keys %dats) {
|
||||
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
|
||||
if ($dat =~ /$Remove_Gcda_Regexp/) {
|
||||
# Remove .gcda/.gcno for files we don't care about before we slowly
|
||||
# read them
|
||||
unlink $dat;
|
||||
unlink $gcno;
|
||||
delete $dats{$dat};
|
||||
next;
|
||||
}
|
||||
}
|
||||
$dats = `find . -print | grep .gcno`;
|
||||
my %gcnos;
|
||||
foreach my $gcno (split '\n', $dats) {
|
||||
(my $gbase = $gcno) =~ s!.*/!!;
|
||||
$gcnos{$gbase} = File::Spec->rel2abs($gcno);
|
||||
}
|
||||
# We need a matching .gcno for every .gcda, try to find a matching file elsewhere
|
||||
foreach my $dat (sort keys %dats) {
|
||||
(my $gcno = $dat) =~ s!\.gcda$!.gcno!;
|
||||
(my $gbase = $gcno) =~ s!.*/!!;
|
||||
if (!-r $gcno) {
|
||||
if ($gcnos{$gbase}) {
|
||||
symlink($gcnos{$gbase}, $gcno)
|
||||
or die "%Error: can't ln -s $gcnos{$gbase} $gcno,";
|
||||
} else {
|
||||
warn "MISSING .gcno for a .gcda: $gcno\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{5} && $Opt_Fastcov) {
|
||||
travis_fold_start("fastcov");
|
||||
# Must run in root directory to find all files
|
||||
mkpath($cc_dir);
|
||||
#run("${RealBin}/fastcov.py -b -c src/obj_dbg -X".
|
||||
# " --exclude /usr --exclude test_regress"
|
||||
# ." -o ${cc_dir}/app_total.json");
|
||||
run("${RealBin}/fastcov.py -b -c src/obj_dbg -X --lcov".
|
||||
" --exclude /usr --exclude test_regress"
|
||||
." -o ${cc_dir}/app_total.info");
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{5} && !$Opt_Fastcov) {
|
||||
travis_fold_start("infos");
|
||||
print "Stage 5: make infos\n";
|
||||
my $dats = `find . -print | grep .gcda`;
|
||||
my %dirs;
|
||||
foreach my $dat (split '\n', $dats) {
|
||||
$dat =~ s!/[^/]+$!!;
|
||||
$dirs{$dat} = 1;
|
||||
(my $dir = $dat) =~ s!/[^/]+$!!;
|
||||
$dirs{$dir} = 1;
|
||||
}
|
||||
|
||||
foreach my $dir (sort keys %dirs) {
|
||||
(my $outname = $dir) =~ s![^a-zA-Z0-9]+!_!g;
|
||||
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir -o app_test_${outname}.info");
|
||||
$Fork->schedule(run_on_start => sub {
|
||||
# .info may be empty, so ignore errors (unfortunately)
|
||||
run("cd $cc_dir/info ; lcov -c -d ../../../../$dir --exclude /usr -o app_test_${outname}.info || true");
|
||||
})->run;
|
||||
}
|
||||
$Fork->wait_all;
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stage <= 3) {
|
||||
# lcov doesn't have a control file to override single lines, so replicate the sources
|
||||
print "Stage 3: Clone sources under $cc_dir\n";
|
||||
if ($Opt_Stages{6}) {
|
||||
travis_fold_start("clone");
|
||||
# No control file to override single lines, so replicate the sources
|
||||
# Also lets us see the insertion markers in the HTML source res
|
||||
print "Stage 6: Clone sources under $cc_dir\n";
|
||||
clone_sources($cc_dir);
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stage <= 4) {
|
||||
print "Stage 4: Copy .gcno files\n";
|
||||
if ($Opt_Stages{8} && !$Opt_Fastcov) {
|
||||
travis_fold_start("copy");
|
||||
print "Stage 8: Copy .gcno files\n";
|
||||
my $dats = `find . -print | grep .gcno`;
|
||||
foreach my $dat (split '\n', $dats) {
|
||||
foreach my $dat (sort (split '\n', $dats)) {
|
||||
next if $dat =~ /$cc_dir/;
|
||||
my $outdat = $cc_dir."/".$dat;
|
||||
#print "cp $dat, $outdat);\n";
|
||||
cp($dat, $outdat);
|
||||
}
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stage <= 5) {
|
||||
print "Stage 5: Combine data files\n";
|
||||
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
|
||||
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
|
||||
my $infos = `cd $cc_dir ; find info -print | grep .info`;
|
||||
my $comb = "";
|
||||
my @infos = (split /\n/, $infos);
|
||||
foreach my $info (@infos) {
|
||||
$comb .= " -a $info";
|
||||
# Need to batch them to avoid overrunning shell command length limit
|
||||
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
|
||||
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info");
|
||||
$comb = "";
|
||||
if ($Opt_Stages{10} && !$Opt_Fastcov) {
|
||||
travis_fold_start("combine");
|
||||
print "Stage 10: Combine data files\n";
|
||||
{
|
||||
run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info");
|
||||
run("cd $cc_dir ; lcov -a app_base.info -o app_total.info");
|
||||
my $infos = `cd $cc_dir ; find info -print | grep .info`;
|
||||
my $comb = "";
|
||||
my @infos = (sort (split /\n/, $infos));
|
||||
foreach my $info (@infos) {
|
||||
$comb .= " -a $info";
|
||||
# Need to batch them to avoid overrunning shell command length limit
|
||||
if (length($comb) > 10000 || $info eq $infos[$#infos]) {
|
||||
# .info may be empty, so ignore errors (unfortunately)
|
||||
run("cd $cc_dir ; lcov -a app_total.info $comb -o app_total.info || true");
|
||||
$comb = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stage <= 6) {
|
||||
print "Stage 6: Filter processed source files\n";
|
||||
my $cmd = '';
|
||||
foreach my $glob (@Remove_Sources) {
|
||||
$cmd .= " '$glob'";
|
||||
if ($Opt_Stages{11}) {
|
||||
travis_fold_start("dirs");
|
||||
print "Stage 11: Cleanup paths\n";
|
||||
if ($Opt_Fastcov) {
|
||||
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
||||
#cleanup_abs_paths_json($cc_dir, "$cc_dir/app_total.json", "$cc_dir/app_total.json");
|
||||
} else {
|
||||
cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
||||
}
|
||||
run("cd $cc_dir ; lcov --remove app_total.info $cmd -o app_total.info");
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stage <= 7) {
|
||||
print "Stage 7: Create HTML\n";
|
||||
cleanup_abs_paths($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info");
|
||||
run("cd $cc_dir ; genhtml app_total.info --demangle-cpp"
|
||||
if ($Opt_Stages{12}) {
|
||||
travis_fold_start("filter");
|
||||
print "Stage 12: Filter processed source files\n";
|
||||
my $inc = '';
|
||||
foreach my $glob (@Source_Globs) {
|
||||
foreach my $infile (glob $glob) {
|
||||
$inc .= " '$infile'";
|
||||
}
|
||||
}
|
||||
my $exc = '';
|
||||
foreach my $glob (@Remove_Sources) {
|
||||
# Fastcov does exact match not globbing at present
|
||||
# Lcov requires whole path match so needs the glob
|
||||
$glob =~ s!^\*!! if $Opt_Fastcov;
|
||||
$glob =~ s!\*$!! if $Opt_Fastcov;
|
||||
$exc .= " '$glob'";
|
||||
}
|
||||
if ($Opt_Fastcov) {
|
||||
$inc = "--include ".$inc if $inc ne '';
|
||||
$exc = "--exclude ".$exc if $exc ne '';
|
||||
run("cd $cc_dir ; ${RealBin}/fastcov.py -C app_total.info ${inc} ${exc} -x --lcov -o app_total_f.info");
|
||||
} else {
|
||||
run("cd $cc_dir ; lcov --remove app_total.info $exc -o app_total_f.info");
|
||||
}
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{17}) {
|
||||
travis_fold_start("report");
|
||||
print "Stage 17: Create HTML\n";
|
||||
run("cd $cc_dir ; genhtml app_total_f.info --demangle-cpp"
|
||||
." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html");
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stage <= 9) {
|
||||
if ($Opt_Stages{18}) {
|
||||
travis_fold_start("upload");
|
||||
print "Stage 18: Upload\n";
|
||||
my $cmd = "bash <(curl -s https://codecov.io/bash) -f $cc_dir/app_total.info";
|
||||
print "print: Not running: export CODECOV_TOKEN=<hidden>\n";
|
||||
print "print: Not running: $cmd\n";
|
||||
travis_fold_end();
|
||||
}
|
||||
|
||||
if ($Opt_Stages{19}) {
|
||||
print "*-* All Finished *-*\n";
|
||||
print "\n";
|
||||
print "* See report in ${cc_dir}/html/index.html\n";
|
||||
print "* Remember to make distclean && ./configure before working on non-coverage\n";
|
||||
}
|
||||
}
|
||||
|
||||
sub clone_sources {
|
||||
my $cc_dir = shift;
|
||||
my $excluded_lines = 0;
|
||||
my $excluded_br_lines = 0;
|
||||
foreach my $glob (@Source_Globs) {
|
||||
foreach my $infile (glob $glob) {
|
||||
$infile !~ m!^/!
|
||||
@@ -145,21 +327,35 @@ sub clone_sources {
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
$lineno++;
|
||||
chomp $line;
|
||||
if ($line !~ m!// LCOV_EXCL_LINE!
|
||||
&& $line =~ /$Exclude_Line_Regexp/) {
|
||||
$line .= " //code_coverage: // LCOV_EXCL_LINE";
|
||||
if ($line =~ /LCOV_EXCL_LINE/) {
|
||||
$line .= " LCOV_EXCL_BR_LINE";
|
||||
}
|
||||
elsif ($line =~ /LCOV_EXCL_START/) {
|
||||
$line .= " LCOV_EXCL_BR_START";
|
||||
}
|
||||
elsif ($line =~ /LCOV_EXCL_STOP/) {
|
||||
$line .= " LCOV_EXCL_BR_STOP";
|
||||
}
|
||||
elsif ($line =~ /$Exclude_Line_Regexp/) {
|
||||
$line .= " //code_coverage: // LCOV_EXCL_LINE LCOV_EXCL_BR_LINE";
|
||||
$excluded_lines++;
|
||||
$excluded_br_lines++;
|
||||
#print "$infile:$lineno: $line";
|
||||
}
|
||||
elsif ($line =~ /$Exclude_Branch_Regexp/) {
|
||||
$line .= " //code_coverage: // LCOV_EXCL_BR_LINE";
|
||||
$excluded_br_lines++;
|
||||
#print "$infile:$lineno: $line";
|
||||
} else {
|
||||
}
|
||||
$ofh->print("$line\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
print "Source code lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
|
||||
print "Number of source lines automatically LCOV_EXCL_LINE'ed: $excluded_lines\n";
|
||||
print "Number of source lines automatically LCOV_EXCL_BR_LINE'ed: $excluded_br_lines\n";
|
||||
}
|
||||
|
||||
sub cleanup_abs_paths {
|
||||
sub cleanup_abs_paths_info {
|
||||
my $cc_dir = shift;
|
||||
my $infile = shift;
|
||||
my $outfile = shift;
|
||||
@@ -178,18 +374,41 @@ sub cleanup_abs_paths {
|
||||
$ofh->print(@lines);
|
||||
}
|
||||
|
||||
sub cleanup_abs_paths_json {
|
||||
my $cc_dir = shift;
|
||||
my $infile = shift;
|
||||
my $outfile = shift;
|
||||
# Handcrafted cleanup, alternative would be to deserialize/serialize JSON
|
||||
# But JSON::Parse not installed by default
|
||||
# JSON::PP more likely to be installed, but slower
|
||||
my $fh = IO::File->new("<$infile") or die "%Error: $! $infile,";
|
||||
my @lines;
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
$line =~ s!"$ENV{VERILATOR_ROOT}/!"!g;
|
||||
$line =~ s!"$cc_dir/!"!g;
|
||||
$line =~ s!obj_dbg/verilog.y$!verilog.y!g;
|
||||
push @lines, $line;
|
||||
}
|
||||
my $ofh = IO::File->new(">$outfile") or die "%Error: $! $outfile,";
|
||||
$ofh->print(@lines);
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
# .dat file callbacks
|
||||
|
||||
sub exclude_branch_regexp {
|
||||
$Exclude_Branch_Regexp = shift;
|
||||
}
|
||||
sub exclude_line_regexp {
|
||||
$Exclude_Line_Regexp = shift;
|
||||
}
|
||||
|
||||
sub remove_gcda_regexp {
|
||||
$Remove_Gcda_Regexp = shift;
|
||||
}
|
||||
sub remove_source {
|
||||
my @srcs = @_;
|
||||
push @Remove_Sources, @srcs;
|
||||
}
|
||||
|
||||
sub source_globs {
|
||||
my @dirs = @_;
|
||||
push @Source_Globs, @dirs;
|
||||
@@ -206,6 +425,15 @@ sub run {
|
||||
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
|
||||
}
|
||||
|
||||
our $_Travis_Action;
|
||||
sub travis_fold_start {
|
||||
$_Travis_Action = shift;
|
||||
print "travis_fold:start:$_Travis_Action\n";
|
||||
}
|
||||
sub travis_fold_end {
|
||||
print "travis_fold:end:$_Travis_Action\n";
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
@@ -231,13 +459,30 @@ This will rebuild the current object files.
|
||||
|
||||
=over 4
|
||||
|
||||
=item --hashset I<hashset>
|
||||
|
||||
Pass test hashset onto driver.pl test harness.
|
||||
|
||||
=item --help
|
||||
|
||||
Displays this message and program version and exits.
|
||||
|
||||
=item -stage I<stage>
|
||||
=item --scenarios I<scenarios>
|
||||
|
||||
Runs a specific stage (see the script).
|
||||
Pass test scenarios onto driver.pl test harness.
|
||||
|
||||
=item --stages I<stage>
|
||||
|
||||
Runs a specific stage or range of stages (see the script).
|
||||
|
||||
=item --no-stop
|
||||
|
||||
Do not stop collecting data if tests fail.
|
||||
|
||||
=item --test I<test_regress_test_name>
|
||||
|
||||
Instead of normal regressions, run the specified test. May be specified
|
||||
multiple times for multiple tests.
|
||||
|
||||
=back
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ source_globs("src/*.cpp",
|
||||
"include/*/*.c",
|
||||
);
|
||||
|
||||
remove_source("/usr/include/*");
|
||||
# Note *'s are removed when using fastcov
|
||||
remove_source("/usr/*");
|
||||
remove_source("*/include/sysc/*");
|
||||
remove_source("*/V3ClkGater.cpp");
|
||||
remove_source("*/V3ClkGater.h");
|
||||
@@ -37,7 +38,25 @@ remove_source("*include/gtkwave/*");
|
||||
remove_source("*test_regress/*");
|
||||
remove_source("*examples/*");
|
||||
|
||||
# Remove collected coverage on each little test main file
|
||||
# Would just be removed with remove_source in later step
|
||||
remove_gcda_regexp(qr!test_regress/.*/(Vt_|Vtop_).*\.gcda!);
|
||||
|
||||
exclude_line_regexp(qr/(\bv3fatalSrc\b|\bVL_UNCOVERABLE\b)/);
|
||||
# Exclude line entirely, also excludes from function and branch coverage
|
||||
exclude_line_regexp(qr/(\bv3fatalSrc\b
|
||||
|\bfatalSrc\b
|
||||
|\bVL_UNCOVERABLE\b
|
||||
|\bVL_UNREACHABLE\b
|
||||
|\bVL_FATAL
|
||||
|\bUASSERT
|
||||
|\bNUM_ASSERT
|
||||
|\bERROR_RSVD_WORD
|
||||
|\bV3ERROR_NA
|
||||
|\bUINFO\b)/x);
|
||||
|
||||
# Exclude for branch coverage only
|
||||
exclude_branch_regexp(qr/(\bdebug\(\)
|
||||
|\bassert\(
|
||||
|\bSELF_CHECK)/x);
|
||||
|
||||
1;
|
||||
|
||||
Executable
+744
@@ -0,0 +1,744 @@
|
||||
#!/usr/bin/env python3
|
||||
# SPDX-License-Identifier: MIT
|
||||
# Copyright 2018-present, Bryan Gillespie
|
||||
"""
|
||||
Author: Bryan Gillespie
|
||||
https://github.com/RPGillespie6/fastcov
|
||||
|
||||
A massively parallel gcov wrapper for generating intermediate coverage formats fast
|
||||
|
||||
The goal of fastcov is to generate code coverage intermediate formats as fast as possible,
|
||||
even for large projects with hundreds of gcda objects. The intermediate formats may then be
|
||||
consumed by a report generator such as lcov's genhtml, or a dedicated frontend such as coveralls.
|
||||
|
||||
Sample Usage:
|
||||
$ cd build_dir
|
||||
$ ./fastcov.py --zerocounters
|
||||
$ <run unit tests>
|
||||
$ ./fastcov.py --exclude /usr/include test/ --lcov -o report.info
|
||||
$ genhtml -o code_coverage report.info
|
||||
"""
|
||||
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
import glob
|
||||
import json
|
||||
import time
|
||||
import logging
|
||||
import argparse
|
||||
import threading
|
||||
import subprocess
|
||||
import multiprocessing
|
||||
|
||||
FASTCOV_VERSION = (1,7)
|
||||
MINIMUM_PYTHON = (3,5)
|
||||
MINIMUM_GCOV = (9,0,0)
|
||||
|
||||
# Interesting metrics
|
||||
START_TIME = time.monotonic()
|
||||
GCOVS_TOTAL = 0
|
||||
GCOVS_SKIPPED = 0
|
||||
|
||||
# For when things go wrong...
|
||||
# Start error codes at 3 because 1-2 are special
|
||||
# See https://stackoverflow.com/a/1535733/2516916
|
||||
EXIT_CODE = 0
|
||||
EXIT_CODES = {
|
||||
"gcov_version": 3,
|
||||
"python_version": 4,
|
||||
"unsupported_coverage_format": 5,
|
||||
"excl_not_found": 6,
|
||||
}
|
||||
|
||||
# Disable all logging in case developers are using this as a module
|
||||
logging.disable(level=logging.CRITICAL)
|
||||
|
||||
class FastcovFormatter(logging.Formatter):
|
||||
def format(self, record):
|
||||
record.levelname = record.levelname.lower()
|
||||
log_message = super(FastcovFormatter, self).format(record)
|
||||
return "[{:.3f}s] {}".format(stopwatch(), log_message)
|
||||
|
||||
def chunks(l, n):
|
||||
"""Yield successive n-sized chunks from l."""
|
||||
for i in range(0, len(l), n):
|
||||
yield l[i:i + n]
|
||||
|
||||
def setExitCode(key):
|
||||
global EXIT_CODE
|
||||
EXIT_CODE = EXIT_CODES[key]
|
||||
|
||||
def incrementCounters(total, skipped):
|
||||
global GCOVS_TOTAL
|
||||
global GCOVS_SKIPPED
|
||||
GCOVS_TOTAL += total
|
||||
GCOVS_SKIPPED += skipped
|
||||
|
||||
def stopwatch():
|
||||
"""Return number of seconds since last time this was called."""
|
||||
global START_TIME
|
||||
end_time = time.monotonic()
|
||||
delta = end_time - START_TIME
|
||||
START_TIME = end_time
|
||||
return delta
|
||||
|
||||
def parseVersionFromLine(version_str):
|
||||
"""Given a string containing a dotted integer version, parse out integers and return as tuple."""
|
||||
version = re.search(r'(\d+\.\d+\.\d+)', version_str)
|
||||
|
||||
if not version:
|
||||
return (0,0,0)
|
||||
|
||||
return tuple(map(int, version.group(1).split(".")))
|
||||
|
||||
def getGcovVersion(gcov):
|
||||
p = subprocess.Popen([gcov, "-v"], stdout=subprocess.PIPE)
|
||||
output = p.communicate()[0].decode('UTF-8')
|
||||
p.wait()
|
||||
return parseVersionFromLine(output.split("\n")[0])
|
||||
|
||||
def removeFiles(files):
|
||||
for file in files:
|
||||
os.remove(file)
|
||||
|
||||
def getFilteredCoverageFiles(coverage_files, exclude):
|
||||
def excludeGcda(gcda):
|
||||
for ex in exclude:
|
||||
if ex in gcda:
|
||||
logging.debug("Omitting %s due to '--exclude-gcda %s'", gcda, ex)
|
||||
return False
|
||||
return True
|
||||
return list(filter(excludeGcda, coverage_files))
|
||||
|
||||
def findCoverageFiles(cwd, coverage_files, use_gcno):
|
||||
coverage_type = "user provided"
|
||||
if not coverage_files:
|
||||
coverage_type = "gcno" if use_gcno else "gcda"
|
||||
coverage_files = glob.glob(os.path.join(os.path.abspath(cwd), "**/*." + coverage_type), recursive=True)
|
||||
|
||||
logging.info("Found {} coverage files ({})".format(len(coverage_files), coverage_type))
|
||||
logging.debug("Coverage files found:\n %s", "\n ".join(coverage_files))
|
||||
return coverage_files
|
||||
|
||||
def gcovWorker(data_q, metrics_q, args, chunk, gcov_filter_options):
|
||||
base_report = {"sources": {}}
|
||||
gcovs_total = 0
|
||||
gcovs_skipped = 0
|
||||
|
||||
gcov_args = "-it"
|
||||
if args.branchcoverage or args.xbranchcoverage:
|
||||
gcov_args += "b"
|
||||
|
||||
p = subprocess.Popen([args.gcov, gcov_args] + chunk, cwd=args.cdirectory, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL)
|
||||
for line in iter(p.stdout.readline, b''):
|
||||
intermediate_json = json.loads(line.decode(sys.stdout.encoding))
|
||||
intermediate_json_files = processGcovs(args.cdirectory, intermediate_json["files"], gcov_filter_options)
|
||||
for f in intermediate_json_files:
|
||||
distillSource(f, base_report["sources"], args.test_name, args.xbranchcoverage)
|
||||
gcovs_total += len(intermediate_json["files"])
|
||||
gcovs_skipped += len(intermediate_json["files"]) - len(intermediate_json_files)
|
||||
|
||||
p.wait()
|
||||
data_q.put(base_report)
|
||||
metrics_q.put((gcovs_total, gcovs_skipped))
|
||||
|
||||
def processGcdas(args, coverage_files, gcov_filter_options):
|
||||
chunk_size = max(args.minimum_chunk, int(len(coverage_files) / args.jobs) + 1)
|
||||
|
||||
processes = []
|
||||
data_q = multiprocessing.Queue()
|
||||
metrics_q = multiprocessing.Queue()
|
||||
for chunk in chunks(coverage_files, chunk_size):
|
||||
p = multiprocessing.Process(target=gcovWorker, args=(data_q, metrics_q, args, chunk, gcov_filter_options))
|
||||
processes.append(p)
|
||||
p.start()
|
||||
|
||||
logging.info("Spawned {} gcov processes, each processing at most {} coverage files".format(len(processes), chunk_size))
|
||||
|
||||
fastcov_jsons = []
|
||||
for p in processes:
|
||||
fastcov_jsons.append(data_q.get())
|
||||
incrementCounters(*metrics_q.get())
|
||||
|
||||
for p in processes:
|
||||
p.join()
|
||||
|
||||
base_fastcov = fastcov_jsons.pop()
|
||||
for fj in fastcov_jsons:
|
||||
combineReports(base_fastcov, fj)
|
||||
|
||||
return base_fastcov
|
||||
|
||||
def shouldFilterSource(source, gcov_filter_options):
|
||||
"""Returns true if the provided source file should be filtered due to CLI options, otherwise returns false."""
|
||||
# If explicit sources were passed, check for match
|
||||
if gcov_filter_options["sources"]:
|
||||
if source not in gcov_filter_options["sources"]:
|
||||
logging.debug("Filtering coverage for '%s' due to option '--source-files'", source)
|
||||
return True
|
||||
|
||||
# Check exclude filter
|
||||
for ex in gcov_filter_options["exclude"]:
|
||||
if ex in source:
|
||||
logging.debug("Filtering coverage for '%s' due to option '--exclude %s'", source, ex)
|
||||
return True
|
||||
|
||||
# Check include filter
|
||||
if gcov_filter_options["include"]:
|
||||
included = False
|
||||
for inc in gcov_filter_options["include"]:
|
||||
if inc in source:
|
||||
included = True
|
||||
break
|
||||
|
||||
if not included:
|
||||
logging.debug("Filtering coverage for '%s' due to option '--include %s'", source, " ".join(gcov_filter_options["include"]))
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def filterFastcov(fastcov_json, args):
|
||||
logging.info("Performing filtering operations (if applicable)")
|
||||
gcov_filter_options = getGcovFilterOptions(args)
|
||||
for source in list(fastcov_json["sources"].keys()):
|
||||
if shouldFilterSource(source, gcov_filter_options):
|
||||
del fastcov_json["sources"][source]
|
||||
|
||||
def processGcov(cwd, gcov, files, gcov_filter_options):
|
||||
# Add absolute path
|
||||
gcov["file_abs"] = os.path.abspath(os.path.join(cwd, gcov["file"]))
|
||||
|
||||
if shouldFilterSource(gcov["file_abs"], gcov_filter_options):
|
||||
return
|
||||
|
||||
files.append(gcov)
|
||||
logging.debug("Accepted coverage for '%s'", gcov["file_abs"])
|
||||
|
||||
def processGcovs(cwd, gcov_files, gcov_filter_options):
|
||||
files = []
|
||||
for gcov in gcov_files:
|
||||
processGcov(cwd, gcov, files, gcov_filter_options)
|
||||
return files
|
||||
|
||||
def dumpBranchCoverageToLcovInfo(f, branches):
|
||||
branch_miss = 0
|
||||
branch_found = 0
|
||||
brda = []
|
||||
for line_num, branch_counts in branches.items():
|
||||
for i, count in enumerate(branch_counts):
|
||||
# Branch (<line number>, <block number>, <branch number>, <taken>)
|
||||
brda.append((line_num, int(i/2), i, count))
|
||||
branch_miss += int(count == 0)
|
||||
branch_found += 1
|
||||
for v in sorted(brda):
|
||||
f.write("BRDA:{},{},{},{}\n".format(*v))
|
||||
f.write("BRF:{}\n".format(branch_found)) # Branches Found
|
||||
f.write("BRH:{}\n".format(branch_found - branch_miss)) # Branches Hit
|
||||
|
||||
def dumpToLcovInfo(fastcov_json, output):
|
||||
with open(output, "w") as f:
|
||||
sources = fastcov_json["sources"]
|
||||
for sf in sorted(sources.keys()):
|
||||
for tn in sorted(sources[sf].keys()):
|
||||
data = sources[sf][tn]
|
||||
f.write("TN:{}\n".format(tn)) #Test Name - used mainly in conjuction with genhtml --show-details
|
||||
f.write("SF:{}\n".format(sf)) #Source File
|
||||
|
||||
fn_miss = 0
|
||||
fn = []
|
||||
fnda = []
|
||||
for function, fdata in data["functions"].items():
|
||||
fn.append((fdata["start_line"], function)) # Function Start Line
|
||||
fnda.append((fdata["execution_count"], function)) # Function Hits
|
||||
fn_miss += int(fdata["execution_count"] == 0)
|
||||
# NOTE: lcov sorts FN, but not FNDA.
|
||||
for v in sorted(fn):
|
||||
f.write("FN:{},{}\n".format(*v))
|
||||
for v in sorted(fnda):
|
||||
f.write("FNDA:{},{}\n".format(*v))
|
||||
f.write("FNF:{}\n".format(len(data["functions"]))) #Functions Found
|
||||
f.write("FNH:{}\n".format((len(data["functions"]) - fn_miss))) #Functions Hit
|
||||
|
||||
if data["branches"]:
|
||||
dumpBranchCoverageToLcovInfo(f, data["branches"])
|
||||
|
||||
line_miss = 0
|
||||
da = []
|
||||
for line_num, count in data["lines"].items():
|
||||
da.append((line_num, count))
|
||||
line_miss += int(count == 0)
|
||||
for v in sorted(da):
|
||||
f.write("DA:{},{}\n".format(*v)) # Line
|
||||
f.write("LF:{}\n".format(len(data["lines"]))) #Lines Found
|
||||
f.write("LH:{}\n".format((len(data["lines"]) - line_miss))) #Lines Hit
|
||||
f.write("end_of_record\n")
|
||||
|
||||
def getSourceLines(source, fallback_encodings=[]):
|
||||
"""Return a list of lines from the provided source, trying to decode with fallback encodings if the default fails."""
|
||||
default_encoding = sys.getdefaultencoding()
|
||||
for encoding in [default_encoding] + fallback_encodings:
|
||||
try:
|
||||
with open(source, encoding=encoding) as f:
|
||||
return f.readlines()
|
||||
except UnicodeDecodeError:
|
||||
pass
|
||||
|
||||
logging.warning("Could not decode '{}' with {} or fallback encodings ({}); ignoring errors".format(source, default_encoding, ",".join(fallback_encodings)))
|
||||
with open(source, errors="ignore") as f:
|
||||
return f.readlines()
|
||||
|
||||
def exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings):
|
||||
start_line = 0
|
||||
end_line = 0
|
||||
# Start enumeration at line 1 because the first line of the file is line 1 not 0
|
||||
for i, line in enumerate(getSourceLines(source, fallback_encodings), 1):
|
||||
# Cycle through test names (likely only 1)
|
||||
for test_name in fastcov_sources[source]:
|
||||
fastcov_data = fastcov_sources[source][test_name]
|
||||
|
||||
# Build line to function dict so can quickly delete by line number
|
||||
line_to_func = {}
|
||||
for f in fastcov_data["functions"].keys():
|
||||
l = fastcov_data["functions"][f]["start_line"]
|
||||
if l not in line_to_func:
|
||||
line_to_func[l] = set()
|
||||
line_to_func[l].add(f)
|
||||
|
||||
if i in fastcov_data["branches"]:
|
||||
del_exclude_br = exclude_branches_sw and any(line.lstrip().startswith(e) for e in exclude_branches_sw)
|
||||
del_include_br = include_branches_sw and all(not line.lstrip().startswith(e) for e in include_branches_sw)
|
||||
if del_exclude_br or del_include_br:
|
||||
del fastcov_data["branches"][i]
|
||||
|
||||
if "LCOV_EXCL" not in line:
|
||||
continue
|
||||
|
||||
if "LCOV_EXCL_LINE" in line:
|
||||
for key in ["lines", "branches"]:
|
||||
if i in fastcov_data[key]:
|
||||
del fastcov_data[key][i]
|
||||
if i in line_to_func:
|
||||
for key in line_to_func[i]:
|
||||
if key in fastcov_data["functions"]:
|
||||
del fastcov_data["functions"][key]
|
||||
elif "LCOV_EXCL_START" in line:
|
||||
start_line = i
|
||||
elif "LCOV_EXCL_STOP" in line:
|
||||
end_line = i
|
||||
|
||||
if not start_line:
|
||||
end_line = 0
|
||||
continue
|
||||
|
||||
for key in ["lines", "branches"]:
|
||||
for line_num in list(fastcov_data[key].keys()):
|
||||
if start_line <= line_num <= end_line:
|
||||
del fastcov_data[key][line_num]
|
||||
|
||||
for line_num in range(start_line, end_line):
|
||||
if line_num in line_to_func:
|
||||
for key in line_to_func[line_num]:
|
||||
if key in fastcov_data["functions"]:
|
||||
del fastcov_data["functions"][key]
|
||||
|
||||
start_line = end_line = 0
|
||||
elif "LCOV_EXCL_BR_LINE" in line:
|
||||
if i in fastcov_data["branches"]:
|
||||
del fastcov_data["branches"][i]
|
||||
|
||||
def exclMarkerWorker(fastcov_sources, chunk, exclude_branches_sw, include_branches_sw, fallback_encodings):
|
||||
for source in chunk:
|
||||
try:
|
||||
exclProcessSource(fastcov_sources, source, exclude_branches_sw, include_branches_sw, fallback_encodings)
|
||||
except FileNotFoundError:
|
||||
logging.error("Could not find '%s' to scan for exclusion markers...", source)
|
||||
setExitCode("excl_not_found") # Set exit code because of error
|
||||
|
||||
def scanExclusionMarkers(fastcov_json, jobs, exclude_branches_sw, include_branches_sw, min_chunk_size, fallback_encodings):
|
||||
chunk_size = max(min_chunk_size, int(len(fastcov_json["sources"]) / jobs) + 1)
|
||||
|
||||
threads = []
|
||||
for chunk in chunks(list(fastcov_json["sources"].keys()), chunk_size):
|
||||
t = threading.Thread(target=exclMarkerWorker, args=(fastcov_json["sources"], chunk, exclude_branches_sw, include_branches_sw, fallback_encodings))
|
||||
threads.append(t)
|
||||
t.start()
|
||||
|
||||
logging.info("Spawned {} threads each scanning at most {} source files".format(len(threads), chunk_size))
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
def distillFunction(function_raw, functions):
|
||||
function_name = function_raw["name"]
|
||||
# NOTE: need to explicitly cast all counts coming from gcov to int - this is because gcov's json library
|
||||
# will pass as scientific notation (i.e. 12+e45)
|
||||
start_line = int(function_raw["start_line"])
|
||||
execution_count = int(function_raw["execution_count"])
|
||||
if function_name not in functions:
|
||||
functions[function_name] = {
|
||||
"start_line": start_line,
|
||||
"execution_count": execution_count
|
||||
}
|
||||
else:
|
||||
functions[function_name]["execution_count"] += execution_count
|
||||
|
||||
def emptyBranchSet(branch1, branch2):
|
||||
return (branch1["count"] == 0 and branch2["count"] == 0)
|
||||
|
||||
def matchingBranchSet(branch1, branch2):
|
||||
return (branch1["count"] == branch2["count"])
|
||||
|
||||
def filterExceptionalBranches(branches):
|
||||
filtered_branches = []
|
||||
exception_branch = False
|
||||
for i in range(0, len(branches), 2):
|
||||
if i+1 >= len(branches):
|
||||
filtered_branches.append(branches[i])
|
||||
break
|
||||
|
||||
# Filter exceptional branch noise
|
||||
if branches[i+1]["throw"]:
|
||||
exception_branch = True
|
||||
continue
|
||||
|
||||
# Filter initializer list noise
|
||||
if exception_branch and emptyBranchSet(branches[i], branches[i+1]) and len(filtered_branches) >= 2 and matchingBranchSet(filtered_branches[-1], filtered_branches[-2]):
|
||||
return []
|
||||
|
||||
filtered_branches.append(branches[i])
|
||||
filtered_branches.append(branches[i+1])
|
||||
|
||||
return filtered_branches
|
||||
|
||||
def distillLine(line_raw, lines, branches, include_exceptional_branches):
|
||||
line_number = int(line_raw["line_number"])
|
||||
count = int(line_raw["count"])
|
||||
if line_number not in lines:
|
||||
lines[line_number] = count
|
||||
else:
|
||||
lines[line_number] += count
|
||||
|
||||
# Filter out exceptional branches by default unless requested otherwise
|
||||
if not include_exceptional_branches:
|
||||
line_raw["branches"] = filterExceptionalBranches(line_raw["branches"])
|
||||
|
||||
# Increment all branch counts
|
||||
for i, branch in enumerate(line_raw["branches"]):
|
||||
if line_number not in branches:
|
||||
branches[line_number] = []
|
||||
blen = len(branches[line_number])
|
||||
glen = len(line_raw["branches"])
|
||||
if blen < glen:
|
||||
branches[line_number] += [0] * (glen - blen)
|
||||
branches[line_number][i] += int(branch["count"])
|
||||
|
||||
def distillSource(source_raw, sources, test_name, include_exceptional_branches):
|
||||
source_name = source_raw["file_abs"]
|
||||
if source_name not in sources:
|
||||
sources[source_name] = {
|
||||
test_name: {
|
||||
"functions": {},
|
||||
"branches": {},
|
||||
"lines": {}
|
||||
}
|
||||
}
|
||||
|
||||
for function in source_raw["functions"]:
|
||||
distillFunction(function, sources[source_name][test_name]["functions"])
|
||||
|
||||
for line in source_raw["lines"]:
|
||||
distillLine(line, sources[source_name][test_name]["lines"], sources[source_name][test_name]["branches"], include_exceptional_branches)
|
||||
|
||||
def dumpToJson(intermediate, output):
|
||||
with open(output, "w") as f:
|
||||
json.dump(intermediate, f)
|
||||
|
||||
def getGcovFilterOptions(args):
|
||||
return {
|
||||
"sources": set([os.path.abspath(s) for s in args.sources]), #Make paths absolute, use set for fast lookups
|
||||
"include": args.includepost,
|
||||
"exclude": args.excludepost,
|
||||
}
|
||||
|
||||
def addDicts(dict1, dict2):
|
||||
"""Add dicts together by value. i.e. addDicts({"a":1,"b":0}, {"a":2}) == {"a":3,"b":0}."""
|
||||
result = {k:v for k,v in dict1.items()}
|
||||
for k,v in dict2.items():
|
||||
if k in result:
|
||||
result[k] += v
|
||||
else:
|
||||
result[k] = v
|
||||
|
||||
return result
|
||||
|
||||
def addLists(list1, list2):
|
||||
"""Add lists together by value. i.e. addLists([1,1], [2,2]) == [3,3]."""
|
||||
# Find big list and small list
|
||||
blist, slist = list(list2), list(list1)
|
||||
if len(list1) > len(list2):
|
||||
blist, slist = slist, blist
|
||||
|
||||
# Overlay small list onto big list
|
||||
for i, b in enumerate(slist):
|
||||
blist[i] += b
|
||||
|
||||
return blist
|
||||
|
||||
def combineReports(base, overlay):
|
||||
for source, scov in overlay["sources"].items():
|
||||
# Combine Source Coverage
|
||||
if source not in base["sources"]:
|
||||
base["sources"][source] = scov
|
||||
continue
|
||||
|
||||
for test_name, tcov in scov.items():
|
||||
# Combine Source Test Name Coverage
|
||||
if test_name not in base["sources"][source]:
|
||||
base["sources"][source][test_name] = tcov
|
||||
continue
|
||||
|
||||
# Drill down and create convenience variable
|
||||
base_data = base["sources"][source][test_name]
|
||||
|
||||
# Combine Line Coverage
|
||||
base_data["lines"] = addDicts(base_data["lines"], tcov["lines"])
|
||||
|
||||
# Combine Branch Coverage
|
||||
for branch, cov in tcov["branches"].items():
|
||||
if branch not in base_data["branches"]:
|
||||
base_data["branches"][branch] = cov
|
||||
else:
|
||||
base_data["branches"][branch] = addLists(base_data["branches"][branch], cov)
|
||||
|
||||
# Combine Function Coverage
|
||||
for function, cov in tcov["functions"].items():
|
||||
if function not in base_data["functions"]:
|
||||
base_data["functions"][function] = cov
|
||||
else:
|
||||
base_data["functions"][function]["execution_count"] += cov["execution_count"]
|
||||
|
||||
def parseInfo(path):
|
||||
"""Parse an lcov .info file into fastcov json."""
|
||||
fastcov_json = {
|
||||
"sources": {}
|
||||
}
|
||||
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
if line.startswith("TN:"):
|
||||
current_test_name = line[3:].strip()
|
||||
elif line.startswith("SF:"):
|
||||
current_sf = line[3:].strip()
|
||||
fastcov_json["sources"][current_sf] = {
|
||||
current_test_name: {
|
||||
"functions": {},
|
||||
"branches": {},
|
||||
"lines": {},
|
||||
}
|
||||
}
|
||||
current_data = fastcov_json["sources"][current_sf][current_test_name]
|
||||
elif line.startswith("FN:"):
|
||||
line_num, function_name = line[3:].strip().split(",")
|
||||
current_data["functions"][function_name] = {}
|
||||
current_data["functions"][function_name]["start_line"] = int(line_num)
|
||||
elif line.startswith("FNDA:"):
|
||||
count, function_name = line[5:].strip().split(",")
|
||||
current_data["functions"][function_name]["execution_count"] = int(count)
|
||||
elif line.startswith("DA:"):
|
||||
line_num, count = line[3:].strip().split(",")
|
||||
current_data["lines"][line_num] = int(count)
|
||||
elif line.startswith("BRDA:"):
|
||||
branch_tokens = line[5:].strip().split(",")
|
||||
line_num, count = branch_tokens[0], branch_tokens[-1]
|
||||
if line_num not in current_data["branches"]:
|
||||
current_data["branches"][line_num] = []
|
||||
current_data["branches"][line_num].append(int(count))
|
||||
|
||||
return fastcov_json
|
||||
|
||||
def convertKeysToInt(report):
|
||||
for source in report["sources"].keys():
|
||||
for test_name in report["sources"][source].keys():
|
||||
report_data = report["sources"][source][test_name]
|
||||
report_data["lines"] = {int(k):v for k,v in report_data["lines"].items()}
|
||||
report_data["branches"] = {int(k):v for k,v in report_data["branches"].items()}
|
||||
|
||||
def parseAndCombine(paths):
|
||||
base_report = {}
|
||||
|
||||
for path in paths:
|
||||
if path.endswith(".json"):
|
||||
with open(path) as f:
|
||||
report = json.load(f)
|
||||
elif path.endswith(".info"):
|
||||
report = parseInfo(path)
|
||||
else:
|
||||
logging.error("Currently only fastcov .json and lcov .info supported for combine operations, aborting due to %s...\n", path)
|
||||
sys.exit(EXIT_CODES["unsupported_coverage_format"])
|
||||
|
||||
# In order for sorting to work later when we serialize,
|
||||
# make sure integer keys are int
|
||||
convertKeysToInt(report)
|
||||
|
||||
if not base_report:
|
||||
base_report = report
|
||||
logging.info("Setting {} as base report".format(path))
|
||||
else:
|
||||
combineReports(base_report, report)
|
||||
logging.info("Adding {} to base report".format(path))
|
||||
|
||||
return base_report
|
||||
|
||||
def getCombineCoverage(args):
|
||||
logging.info("Performing combine operation")
|
||||
fastcov_json = parseAndCombine(args.combine)
|
||||
filterFastcov(fastcov_json, args)
|
||||
return fastcov_json
|
||||
|
||||
def getGcovCoverage(args):
|
||||
# Need at least python 3.5 because of use of recursive glob
|
||||
checkPythonVersion(sys.version_info[0:2])
|
||||
|
||||
# Need at least gcov 9.0.0 because that's when gcov JSON and stdout streaming was introduced
|
||||
checkGcovVersion(getGcovVersion(args.gcov))
|
||||
|
||||
# Get list of gcda files to process
|
||||
coverage_files = findCoverageFiles(args.directory, args.coverage_files, args.use_gcno)
|
||||
|
||||
# If gcda/gcno filtering is enabled, filter them out now
|
||||
if args.excludepre:
|
||||
coverage_files = getFilteredCoverageFiles(coverage_files, args.excludepre)
|
||||
logging.info("Found {} coverage files after filtering".format(len(coverage_files)))
|
||||
|
||||
# We "zero" the "counters" by simply deleting all gcda files
|
||||
if args.zerocounters:
|
||||
removeFiles(coverage_files)
|
||||
logging.info("Removed {} .gcda files".format(len(coverage_files)))
|
||||
sys.exit()
|
||||
|
||||
# Fire up one gcov per cpu and start processing gcdas
|
||||
gcov_filter_options = getGcovFilterOptions(args)
|
||||
fastcov_json = processGcdas(args, coverage_files, gcov_filter_options)
|
||||
|
||||
# Summarize processing results
|
||||
logging.info("Processed {} .gcov files ({} total, {} skipped)".format(GCOVS_TOTAL - GCOVS_SKIPPED, GCOVS_TOTAL, GCOVS_SKIPPED))
|
||||
logging.debug("Final report will contain coverage for the following %d source files:\n %s", len(fastcov_json["sources"]), "\n ".join(fastcov_json["sources"]))
|
||||
|
||||
return fastcov_json
|
||||
|
||||
def dumpFile(fastcov_json, args):
|
||||
if args.lcov:
|
||||
dumpToLcovInfo(fastcov_json, args.output)
|
||||
logging.info("Created lcov info file '{}'".format(args.output))
|
||||
else:
|
||||
dumpToJson(fastcov_json, args.output)
|
||||
logging.info("Created fastcov json file '{}'".format(args.output))
|
||||
|
||||
def tupleToDotted(tup):
|
||||
return ".".join(map(str, tup))
|
||||
|
||||
def parseArgs():
|
||||
parser = argparse.ArgumentParser(description='A parallel gcov wrapper for fast coverage report generation')
|
||||
parser.add_argument('-z', '--zerocounters', dest='zerocounters', action="store_true", help='Recursively delete all gcda files')
|
||||
|
||||
# Enable Branch Coverage
|
||||
parser.add_argument('-b', '--branch-coverage', dest='branchcoverage', action="store_true", help='Include only the most useful branches in the coverage report.')
|
||||
parser.add_argument('-B', '--exceptional-branch-coverage', dest='xbranchcoverage', action="store_true", help='Include ALL branches in the coverage report (including potentially noisy exceptional branches).')
|
||||
parser.add_argument('-A', '--exclude-br-lines-starting-with', dest='exclude_branches_sw', nargs="+", metavar='', default=[], help='Exclude branches from lines starting with one of the provided strings (i.e. assert, return, etc.)')
|
||||
parser.add_argument('-a', '--include-br-lines-starting-with', dest='include_branches_sw', nargs="+", metavar='', default=[], help='Include only branches from lines starting with one of the provided strings (i.e. if, else, while, etc.)')
|
||||
parser.add_argument('-X', '--skip-exclusion-markers', dest='skip_exclusion_markers', action="store_true", help='Skip reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
|
||||
parser.add_argument('-x', '--scan-exclusion-markers', dest='scan_exclusion_markers', action="store_true", help='(Combine operations) Force reading source files to search for lcov exclusion markers (such as "LCOV_EXCL_LINE")')
|
||||
|
||||
# Capture untested file coverage as well via gcno
|
||||
parser.add_argument('-n', '--process-gcno', dest='use_gcno', action="store_true", help='Process both gcno and gcda coverage files. This option is useful for capturing untested files in the coverage report.')
|
||||
|
||||
# Filtering Options
|
||||
parser.add_argument('-s', '--source-files', dest='sources', nargs="+", metavar='', default=[], help='Filter: Specify exactly which source files should be included in the final report. Paths must be either absolute or relative to current directory.')
|
||||
parser.add_argument('-e', '--exclude', dest='excludepost', nargs="+", metavar='', default=[], help='Filter: Exclude source files from final report if they contain one of the provided substrings (i.e. /usr/include test/, etc.)')
|
||||
parser.add_argument('-i', '--include', dest='includepost', nargs="+", metavar='', default=[], help='Filter: Only include source files in final report that contain one of the provided substrings (i.e. src/ etc.)')
|
||||
parser.add_argument('-f', '--gcda-files', dest='coverage_files', nargs="+", metavar='', default=[], help='Filter: Specify exactly which gcda or gcno files should be processed. Note that specifying gcno causes both gcno and gcda to be processed.')
|
||||
parser.add_argument('-E', '--exclude-gcda', dest='excludepre', nargs="+", metavar='', default=[], help='Filter: Exclude gcda or gcno files from being processed via simple find matching (not regex)')
|
||||
|
||||
parser.add_argument('-g', '--gcov', dest='gcov', default='gcov', help='Which gcov binary to use')
|
||||
|
||||
parser.add_argument('-d', '--search-directory', dest='directory', default=".", help='Base directory to recursively search for gcda files (default: .)')
|
||||
parser.add_argument('-c', '--compiler-directory', dest='cdirectory', default=".", help='Base directory compiler was invoked from (default: .) \
|
||||
This needs to be set if invoking fastcov from somewhere other than the base compiler directory.')
|
||||
|
||||
parser.add_argument('-j', '--jobs', dest='jobs', type=int, default=multiprocessing.cpu_count(), help='Number of parallel gcov to spawn (default: {}).'.format(multiprocessing.cpu_count()))
|
||||
parser.add_argument('-m', '--minimum-chunk-size', dest='minimum_chunk', type=int, default=5, help='Minimum number of files a thread should process (default: 5). \
|
||||
If you have only 4 gcda files but they are monstrously huge, you could change this value to a 1 so that each thread will only process 1 gcda. Otherwise fastcov will spawn only 1 thread to process all of them.')
|
||||
|
||||
parser.add_argument('-F', '--fallback-encodings', dest='fallback_encodings', nargs="+", metavar='', default=[], help='List of encodings to try if opening a source file with the default fails (i.e. latin1, etc.). This option is not usually needed.')
|
||||
|
||||
parser.add_argument('-l', '--lcov', dest='lcov', action="store_true", help='Output in lcov info format instead of fastcov json')
|
||||
parser.add_argument('-o', '--output', dest='output', default="coverage.json", help='Name of output file (default: coverage.json)')
|
||||
parser.add_argument('-q', '--quiet', dest='quiet', action="store_true", help='Suppress output to stdout')
|
||||
|
||||
parser.add_argument('-t', '--test-name', dest='test_name', default="", help='Specify a test name for the coverage. Equivalent to lcov\'s `-t`.')
|
||||
parser.add_argument('-C', '--add-tracefile', dest='combine', nargs="+", help='Combine multiple coverage files into one. If this flag is specified, fastcov will do a combine operation instead invoking gcov. Equivalent to lcov\'s `-a`.')
|
||||
|
||||
parser.add_argument('-V', '--verbose', dest="verbose", action="store_true", help="Print more detailed information about what fastcov is doing")
|
||||
parser.add_argument('-v', '--version', action="version", version='%(prog)s {version}'.format(version=__version__), help="Show program's version number and exit")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
return args
|
||||
|
||||
def checkPythonVersion(version):
|
||||
"""Exit if the provided python version is less than the supported version."""
|
||||
if version < MINIMUM_PYTHON:
|
||||
sys.stderr.write("Minimum python version {} required, found {}\n".format(tupleToDotted(MINIMUM_PYTHON), tupleToDotted(version)))
|
||||
sys.exit(EXIT_CODES["python_version"])
|
||||
|
||||
def checkGcovVersion(version):
|
||||
"""Exit if the provided gcov version is less than the supported version."""
|
||||
if version < MINIMUM_GCOV:
|
||||
sys.stderr.write("Minimum gcov version {} required, found {}\n".format(tupleToDotted(MINIMUM_GCOV), tupleToDotted(version)))
|
||||
sys.exit(EXIT_CODES["gcov_version"])
|
||||
|
||||
def setupLogging(quiet, verbose):
|
||||
handler = logging.StreamHandler()
|
||||
handler.setFormatter(FastcovFormatter("[%(levelname)s]: %(message)s"))
|
||||
|
||||
root = logging.getLogger()
|
||||
root.setLevel(logging.INFO)
|
||||
root.addHandler(handler)
|
||||
|
||||
if not quiet:
|
||||
logging.disable(level=logging.NOTSET) # Re-enable logging
|
||||
|
||||
if verbose:
|
||||
root.setLevel(logging.DEBUG)
|
||||
|
||||
def main():
|
||||
args = parseArgs()
|
||||
|
||||
# Setup logging
|
||||
setupLogging(args.quiet, args.verbose)
|
||||
|
||||
# Get report from appropriate source
|
||||
if args.combine:
|
||||
fastcov_json = getCombineCoverage(args)
|
||||
skip_exclusion_markers = not args.scan_exclusion_markers
|
||||
else:
|
||||
fastcov_json = getGcovCoverage(args)
|
||||
skip_exclusion_markers = args.skip_exclusion_markers
|
||||
|
||||
# Scan for exclusion markers
|
||||
if not skip_exclusion_markers:
|
||||
scanExclusionMarkers(fastcov_json, args.jobs, args.exclude_branches_sw, args.include_branches_sw, args.minimum_chunk, args.fallback_encodings)
|
||||
logging.info("Scanned {} source files for exclusion markers".format(len(fastcov_json["sources"])))
|
||||
|
||||
# Dump to desired file format
|
||||
dumpFile(fastcov_json, args)
|
||||
|
||||
# If there was an error along the way, but we still completed the pipeline...
|
||||
if EXIT_CODE:
|
||||
sys.exit(EXIT_CODE)
|
||||
|
||||
# Set package version... it's way down here so that we can call tupleToDotted
|
||||
__version__ = tupleToDotted(FASTCOV_VERSION)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -1,257 +0,0 @@
|
||||
#!/usr/bin/env perl
|
||||
# See copyright, etc in below POD section.
|
||||
######################################################################
|
||||
|
||||
use warnings;
|
||||
use Getopt::Long;
|
||||
#use Data::Dumper; $Data::Dumper::Indent=1; $Data::Dumper::Sortkeys=1; #Debug
|
||||
use IO::File;
|
||||
use IO::Dir;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw($Debug);
|
||||
|
||||
our $VERSION = '0.001';
|
||||
our $Opt_Widen = 1;
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config("no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"help" => sub { print "Version $VERSION\n";
|
||||
pod2usage(-verbose=>2, -exitval => 0,
|
||||
output=>\*STDOUT, -noperldoc=>1); },
|
||||
"narrow!" => sub { $Opt_Widen = 0; },
|
||||
"version" => sub { print "Version $VERSION\n"; exit(0); },
|
||||
"widen!" => sub { $Opt_Widen = 1; }, # Default, undocumented
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'git_untabify --help'\n";
|
||||
}
|
||||
|
||||
read_patch();
|
||||
|
||||
#######################################################################
|
||||
|
||||
sub read_patch {
|
||||
my $filename = undef;
|
||||
my $lineno = 0;
|
||||
my $hunk = 0;
|
||||
my $editlines = {};
|
||||
while (defined(my $line = <STDIN>)) {
|
||||
chomp $line;
|
||||
if ($line =~ m!^\+\+\+ b/(.*)!) {
|
||||
find_edits($editlines);
|
||||
edit_file($filename, $editlines);
|
||||
$filename = $1;
|
||||
$lineno = 0;
|
||||
$editlines = {};
|
||||
print "FILE $filename\n" if $Debug;
|
||||
}
|
||||
elsif ($line =~ m!^@@ -?[0-9]+,?[0-9]* \+?([0-9]+)!) {
|
||||
$lineno = $1 - 1;
|
||||
++$hunk;
|
||||
print " LINE $1 $line" if $Debug;
|
||||
}
|
||||
elsif ($line =~ m!^ !) {
|
||||
++$lineno;
|
||||
$editlines->{$lineno} = {line => $line,
|
||||
hunk => $hunk,
|
||||
user_edit => 0, };
|
||||
}
|
||||
elsif ($line =~ m!^\+!) {
|
||||
++$lineno;
|
||||
print " $lineno: $line" if $Debug;
|
||||
$editlines->{$lineno} = {line => $line,
|
||||
hunk => $hunk,
|
||||
user_edit => 1, };
|
||||
}
|
||||
}
|
||||
find_edits($editlines);
|
||||
edit_file($filename, $editlines);
|
||||
}
|
||||
|
||||
sub find_edits {
|
||||
my $editlines = shift;
|
||||
# Expand edit regions so if have edited line, non-edited line, edited
|
||||
# line, we will tab expand the middle ones.
|
||||
my %hunk_firstlines;
|
||||
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
|
||||
my $hunk = $editlines->{$lineno}{hunk};
|
||||
$hunk_firstlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
|
||||
}
|
||||
my %hunk_lastlines;
|
||||
foreach my $lineno (sort {$b <=> $a} keys %$editlines) {
|
||||
my $hunk = $editlines->{$lineno}{hunk};
|
||||
$hunk_lastlines{$hunk} ||= $lineno if $editlines->{$lineno}{user_edit};
|
||||
}
|
||||
|
||||
if ($Opt_Widen) {
|
||||
# Expand to include }'s that finish basic block
|
||||
foreach my $hunk (keys %hunk_lastlines) {
|
||||
while (my $lineno = $hunk_lastlines{$hunk}) {
|
||||
++$lineno;
|
||||
if (($editlines->{$lineno}{line} || "")
|
||||
=~ /^[+ ]\s+}[ \t};]*$/) {
|
||||
$hunk_lastlines{$hunk} = $lineno;
|
||||
} else {
|
||||
last;
|
||||
}
|
||||
}
|
||||
}
|
||||
# Expand to always untabify at least 3 lines (so that future diff will
|
||||
# have non-tabs within a edit hunk distance
|
||||
foreach my $hunk (keys %hunk_firstlines) {
|
||||
if ($hunk_firstlines{$hunk} == $hunk_lastlines{$hunk}) {
|
||||
--$hunk_firstlines{$hunk};
|
||||
++$hunk_lastlines{$hunk};
|
||||
}
|
||||
elsif ($hunk_firstlines{$hunk}+1 == $hunk_lastlines{$hunk}) {
|
||||
++$hunk_lastlines{$hunk};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
|
||||
if (($editlines->{$lineno}{line}||"") =~ /\t/) {
|
||||
my $hunk = $editlines->{$lineno}{hunk};
|
||||
if ($hunk_firstlines{$hunk} <= $lineno && $hunk_lastlines{$hunk} >= $lineno) {
|
||||
$editlines->{$lineno}{editit} = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub edit_file {
|
||||
my $filename = shift;
|
||||
my $editlines = shift;
|
||||
|
||||
my @editits;
|
||||
foreach my $lineno (sort {$a <=> $b} keys %$editlines) {
|
||||
push @editits, $lineno if $editlines->{$lineno}{editit};
|
||||
}
|
||||
|
||||
return if $#editits < 0;
|
||||
if (ignore($filename)) {
|
||||
print "%Warning: Ignoring $filename\n";
|
||||
return;
|
||||
}
|
||||
print "Edit $filename ",join(",",@editits),"\n";
|
||||
|
||||
my $lineno = 0;
|
||||
my @out;
|
||||
{
|
||||
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
++$lineno;
|
||||
if ($editlines->{$lineno}{editit}) {
|
||||
print $line;
|
||||
push @out, untabify($line);
|
||||
} else {
|
||||
push @out, $line;
|
||||
}
|
||||
}
|
||||
$fh->close;
|
||||
}
|
||||
{
|
||||
my $fh = IO::File->new(">${filename}.untab") or die "%Error: $! ${filename}.untab,";
|
||||
$fh->print(join('',@out));
|
||||
$fh->close;
|
||||
|
||||
my ($dev,$ino,$mode) = stat($filename);
|
||||
chmod $mode, "${filename}.untab";
|
||||
}
|
||||
|
||||
rename("${filename}.untab", $filename) or die "%Error: $! ${filename}.untab,";
|
||||
}
|
||||
|
||||
sub ignore {
|
||||
my $filename = shift;
|
||||
return 1 if ($filename =~ /(Makefile|\.mk)/);
|
||||
return 1 if ($filename =~ /\.(y|l|out|vcd)$/);
|
||||
return 1 if ($filename =~ /gtkwave/);
|
||||
#
|
||||
return 0 if ($filename =~ /\.(sv|v|vh|svh|h|vc|cpp|pl)$/);
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub untabify {
|
||||
my $line = shift;
|
||||
my $out = "";
|
||||
my $col = 0;
|
||||
foreach my $c (split //, $line) {
|
||||
if ($c eq "\t") {
|
||||
my $destcol = int(($col+8)/8)*8;
|
||||
while ($col < $destcol) { ++$col; $out .= " "; }
|
||||
} else {
|
||||
$out .= $c;
|
||||
$col++;
|
||||
}
|
||||
}
|
||||
return $out;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
git_untabify - Pipe a git diff report and untabify differences
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
git diff a..b | git_untabify
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Take a patch file, and edit the files in the destination patch list to
|
||||
untabify the related patch lines.
|
||||
|
||||
=head1 ARGUMENTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item --help
|
||||
|
||||
Displays this message and program version and exits.
|
||||
|
||||
=item --narrow
|
||||
|
||||
Only edit lines which the user edited.
|
||||
|
||||
If not provided, also edit other lines within at least a 3 line area around
|
||||
the edit, and between any edits within the same hunk.
|
||||
|
||||
=item --version
|
||||
|
||||
Displays program version and exits.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2020 by Wilson Snyder. This program is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "./git_untabify "
|
||||
### End:
|
||||
+12
-7
@@ -69,22 +69,27 @@ dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg
|
||||
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
|
||||
$(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
|
||||
|
||||
ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit
|
||||
ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users
|
||||
GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD
|
||||
endif
|
||||
endif
|
||||
|
||||
prefiles::
|
||||
prefiles:: config_rev.h
|
||||
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
|
||||
# This output goes into srcdir if locally configured, as we need to distribute it as part of the kit.
|
||||
config_rev.h: ${srcdir}/config_rev.pl ${srcdir}/../.git/logs/HEAD
|
||||
config_rev.h: ${srcdir}/config_rev.pl $(GIT_CHANGE_DEP)
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
else
|
||||
config_rev.h: ${srcdir}/config_rev.pl
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
endif
|
||||
|
||||
# Human convenience
|
||||
clang-format:
|
||||
$(MAKE) -C .. $@
|
||||
|
||||
maintainer-copy::
|
||||
clean mostlyclean distclean maintainer-clean::
|
||||
-rm -rf obj_* *.log *.dmp *.vpd core
|
||||
-rm -f *.o *.d perlxsi.c *_gen_*
|
||||
-rm -f *__gen*
|
||||
-rm -f *__gen* obj_*
|
||||
-rm -f .objcache*
|
||||
|
||||
distclean maintainer-clean::
|
||||
|
||||
+13
-7
@@ -42,6 +42,7 @@ LEX = @LEX@
|
||||
LFLAGS = -d
|
||||
PERL = @PERL@
|
||||
YACC = @YACC@
|
||||
OBJCACHE ?= @OBJCACHE@
|
||||
|
||||
prefix = @prefix@
|
||||
|
||||
@@ -167,6 +168,7 @@ RAW_OBJS = \
|
||||
V3Cast.o \
|
||||
V3Cdc.o \
|
||||
V3Changed.o \
|
||||
V3Class.o \
|
||||
V3Clean.o \
|
||||
V3Clock.o \
|
||||
V3Combine.o \
|
||||
@@ -183,6 +185,7 @@ RAW_OBJS = \
|
||||
V3EmitCInlines.o \
|
||||
V3EmitCSyms.o \
|
||||
V3EmitCMake.o \
|
||||
V3EmitCMain.o \
|
||||
V3EmitMk.o \
|
||||
V3EmitV.o \
|
||||
V3EmitXml.o \
|
||||
@@ -200,6 +203,7 @@ RAW_OBJS = \
|
||||
V3GraphPathChecker.o \
|
||||
V3GraphTest.o \
|
||||
V3Hashed.o \
|
||||
V3HierBlock.o \
|
||||
V3Inline.o \
|
||||
V3Inst.o \
|
||||
V3InstrCount.o \
|
||||
@@ -208,11 +212,13 @@ RAW_OBJS = \
|
||||
V3LinkCells.o \
|
||||
V3LinkDot.o \
|
||||
V3LinkJump.o \
|
||||
V3LinkInc.o \
|
||||
V3LinkLValue.o \
|
||||
V3LinkLevel.o \
|
||||
V3LinkParse.o \
|
||||
V3LinkResolve.o \
|
||||
V3Localize.o \
|
||||
V3MergeCond.o \
|
||||
V3Name.o \
|
||||
V3Number.o \
|
||||
V3Options.o \
|
||||
@@ -243,6 +249,7 @@ RAW_OBJS = \
|
||||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3Waiver.o \
|
||||
V3Width.o \
|
||||
V3WidthSel.o \
|
||||
|
||||
@@ -272,7 +279,6 @@ V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
|
||||
|
||||
$(TGT): $(PREDEP_H) $(OBJS)
|
||||
@echo " Linking $@..."
|
||||
-rm -rf $@ [email protected]
|
||||
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
|
||||
|
||||
V3Number_test: V3Number_test.o
|
||||
@@ -284,21 +290,21 @@ V3Number_test: V3Number_test.o
|
||||
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
|
||||
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $<
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
%.o: %.c
|
||||
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $<
|
||||
$(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@
|
||||
|
||||
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $<
|
||||
$(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@
|
||||
|
||||
#### Generated files
|
||||
|
||||
|
||||
+109
-124
@@ -36,7 +36,7 @@
|
||||
#include "V3Const.h"
|
||||
#include "V3SenTree.h" // for SenTreeSet
|
||||
|
||||
#include VL_INCLUDE_UNORDERED_MAP
|
||||
#include <unordered_map>
|
||||
|
||||
//***** See below for main transformation engine
|
||||
|
||||
@@ -50,38 +50,37 @@ protected:
|
||||
|
||||
class ActiveNamer : public ActiveBaseVisitor {
|
||||
private:
|
||||
typedef std::map<string,AstActive*> ActiveNameMap;
|
||||
// STATE
|
||||
AstScope* m_scopep; // Current scope to add statement to
|
||||
AstActive* m_iActivep; // For current scope, the IActive we're building
|
||||
AstActive* m_cActivep; // For current scope, the SActive(combo) we're building
|
||||
AstScope* m_scopep = nullptr; // Current scope to add statement to
|
||||
AstActive* m_iActivep = nullptr; // For current scope, the IActive we're building
|
||||
AstActive* m_cActivep = nullptr; // For current scope, the SActive(combo) we're building
|
||||
|
||||
SenTreeSet m_activeSens; // Sen lists for each active we've made
|
||||
typedef vl_unordered_map<AstSenTree*, AstActive*> ActiveMap;
|
||||
typedef std::unordered_map<AstSenTree*, AstActive*> ActiveMap;
|
||||
ActiveMap m_activeMap; // Map sentree to active, for folding.
|
||||
|
||||
// METHODS
|
||||
void addActive(AstActive* nodep) {
|
||||
UASSERT_OBJ(m_scopep, nodep, "NULL scope");
|
||||
UASSERT_OBJ(m_scopep, nodep, "nullptr scope");
|
||||
m_scopep->addActivep(nodep);
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
m_scopep = nodep;
|
||||
m_iActivep = NULL;
|
||||
m_cActivep = NULL;
|
||||
m_iActivep = nullptr;
|
||||
m_cActivep = nullptr;
|
||||
m_activeSens.clear();
|
||||
m_activeMap.clear();
|
||||
iterateChildren(nodep);
|
||||
// Don't clear scopep, the namer persists beyond this visit
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenTree* nodep) override {
|
||||
// Simplify sensitivity list
|
||||
VL_DO_DANGLING(V3Const::constifyExpensiveEdit(nodep), nodep);
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNodeStmt*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeStmt*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// METHODS
|
||||
@@ -89,8 +88,7 @@ public:
|
||||
AstActive* getCActive(FileLine* fl) {
|
||||
if (!m_cActivep) {
|
||||
m_cActivep = new AstActive(
|
||||
fl, "combo",
|
||||
new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Combo())));
|
||||
fl, "combo", new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Combo())));
|
||||
m_cActivep->sensesStorep(m_cActivep->sensesp());
|
||||
addActive(m_cActivep);
|
||||
}
|
||||
@@ -99,8 +97,7 @@ public:
|
||||
AstActive* getIActive(FileLine* fl) {
|
||||
if (!m_iActivep) {
|
||||
m_iActivep = new AstActive(
|
||||
fl, "initial",
|
||||
new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Initial())));
|
||||
fl, "initial", new AstSenTree(fl, new AstSenItem(fl, AstSenItem::Initial())));
|
||||
m_iActivep->sensesStorep(m_iActivep->sensesp());
|
||||
addActive(m_iActivep);
|
||||
}
|
||||
@@ -109,10 +106,10 @@ public:
|
||||
AstActive* getActive(FileLine* fl, AstSenTree* sensesp) {
|
||||
// Return a sentree in this scope that matches given sense list.
|
||||
|
||||
AstActive* activep = NULL;
|
||||
AstActive* activep = nullptr;
|
||||
AstSenTree* activeSenp = m_activeSens.find(sensesp);
|
||||
if (activeSenp) {
|
||||
ActiveMap::iterator it = m_activeMap.find(activeSenp);
|
||||
const auto it = m_activeMap.find(activeSenp);
|
||||
UASSERT(it != m_activeMap.end(), "Corrupt active map");
|
||||
activep = it->second;
|
||||
}
|
||||
@@ -122,7 +119,7 @@ public:
|
||||
AstSenTree* newsenp = sensesp->cloneTree(false);
|
||||
activep = new AstActive(fl, "sequent", newsenp);
|
||||
activep->sensesStorep(activep->sensesp());
|
||||
UINFO(8," New ACTIVE "<<activep<<endl);
|
||||
UINFO(8, " New ACTIVE " << activep << endl);
|
||||
// Form the sensitivity list
|
||||
addActive(activep);
|
||||
m_activeMap[newsenp] = activep;
|
||||
@@ -131,17 +128,11 @@ public:
|
||||
}
|
||||
return activep;
|
||||
}
|
||||
public:
|
||||
|
||||
// CONSTRUCTORS
|
||||
ActiveNamer() {
|
||||
m_scopep = NULL;
|
||||
m_iActivep = NULL;
|
||||
m_cActivep = NULL;
|
||||
}
|
||||
virtual ~ActiveNamer() {}
|
||||
void main(AstScope* nodep) {
|
||||
iterate(nodep);
|
||||
}
|
||||
ActiveNamer() {}
|
||||
virtual ~ActiveNamer() override {}
|
||||
void main(AstScope* nodep) { iterate(nodep); }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -149,34 +140,36 @@ public:
|
||||
|
||||
class ActiveDlyVisitor : public ActiveBaseVisitor {
|
||||
public:
|
||||
enum CheckType { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
|
||||
enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH };
|
||||
|
||||
private:
|
||||
CheckType m_check; // Combo logic or other
|
||||
AstNode* m_alwaysp; // Always we're under
|
||||
AstNode* m_assignp; // In assign
|
||||
CheckType m_check; // Combo logic or other
|
||||
AstNode* m_alwaysp; // Always we're under
|
||||
AstNode* m_assignp = nullptr; // In assign
|
||||
// VISITORS
|
||||
virtual void visit(AstAssignDly* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignDly* nodep) override {
|
||||
if (m_check != CT_SEQ) {
|
||||
// Convert to a non-delayed assignment
|
||||
UINFO(5," ASSIGNDLY "<<nodep<<endl);
|
||||
UINFO(5, " ASSIGNDLY " << nodep << endl);
|
||||
if (m_check == CT_INITIAL) {
|
||||
nodep->v3warn(INITIALDLY, "Delayed assignments (<=) in initial or final block\n"
|
||||
<<nodep->warnMore()<<"... Suggest blocking assignments (=)");
|
||||
<< nodep->warnMore()
|
||||
<< "... Suggest blocking assignments (=)");
|
||||
} else if (m_check == CT_LATCH) {
|
||||
// Suppress. Shouldn't matter that the interior of the latch races
|
||||
} else {
|
||||
nodep->v3warn(COMBDLY, "Delayed assignments (<=) in non-clocked"
|
||||
" (non flop or latch) block\n"
|
||||
<<nodep->warnMore()<<"... Suggest blocking assignments (=)");
|
||||
" (non flop or latch) block\n"
|
||||
<< nodep->warnMore()
|
||||
<< "... Suggest blocking assignments (=)");
|
||||
}
|
||||
AstNode* newp = new AstAssign(nodep->fileline(),
|
||||
nodep->lhsp()->unlinkFrBack(),
|
||||
AstNode* newp = new AstAssign(nodep->fileline(), nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssign* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssign* nodep) override {
|
||||
if (m_check == CT_SEQ) {
|
||||
AstNode* las = m_assignp;
|
||||
m_assignp = nodep;
|
||||
@@ -184,35 +177,35 @@ private:
|
||||
m_assignp = las;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstVarRef* nodep) override {
|
||||
AstVar* varp = nodep->varp();
|
||||
if (m_check == CT_SEQ
|
||||
&& m_assignp
|
||||
&& !varp->isUsedLoopIdx() // Ignore loop indices
|
||||
if (m_check == CT_SEQ && m_assignp && !varp->isUsedLoopIdx() // Ignore loop indices
|
||||
&& !varp->isTemp()) {
|
||||
// Allow turning off warnings on the always, or the variable also
|
||||
if (!m_alwaysp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
||||
&& !m_assignp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)
|
||||
&& !varp->fileline()->warnIsOff(V3ErrorCode::BLKSEQ)) {
|
||||
m_assignp->v3warn(BLKSEQ, "Blocking assignments (=) in sequential (flop or latch) block\n"
|
||||
<<m_assignp->warnMore()<<"... Suggest delayed assignments (<=)");
|
||||
m_alwaysp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always
|
||||
m_assignp->v3warn(BLKSEQ,
|
||||
"Blocking assignments (=) in sequential (flop or latch) block\n"
|
||||
<< m_assignp->warnMore()
|
||||
<< "... Suggest delayed assignments (<=)");
|
||||
m_alwaysp->fileline()->modifyWarnOff(
|
||||
V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always
|
||||
varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
ActiveDlyVisitor(AstNode* nodep, CheckType check) {
|
||||
m_alwaysp = nodep;
|
||||
m_check = check;
|
||||
m_assignp = NULL;
|
||||
ActiveDlyVisitor(AstNode* nodep, CheckType check)
|
||||
: m_check{check}
|
||||
, m_alwaysp{nodep} {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ActiveDlyVisitor() {}
|
||||
virtual ~ActiveDlyVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -225,67 +218,66 @@ private:
|
||||
// AstNode::user4() Used by V3Const::constify, called below
|
||||
|
||||
// STATE
|
||||
ActiveNamer m_namer; // Tracking of active names
|
||||
AstCFunc* m_scopeFinalp; // Final function for this scope
|
||||
bool m_itemCombo; // Found a SenItem combo
|
||||
bool m_itemSequent; // Found a SenItem sequential
|
||||
ActiveNamer m_namer; // Tracking of active names
|
||||
AstCFunc* m_scopeFinalp = nullptr; // Final function for this scope
|
||||
bool m_itemCombo = false; // Found a SenItem combo
|
||||
bool m_itemSequent = false; // Found a SenItem sequential
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstScope* nodep) override {
|
||||
// Create required actives and add to scope
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
UINFO(4, " SCOPE " << nodep << endl);
|
||||
// Clear last scope's names, and collect this scope's existing names
|
||||
m_namer.main(nodep);
|
||||
m_scopeFinalp = NULL;
|
||||
m_scopeFinalp = nullptr;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
// Actives are being formed, so we can ignore any already made
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstInitial* nodep) override {
|
||||
// Relink to IACTIVE, unless already under it
|
||||
UINFO(4," INITIAL "<<nodep<<endl);
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||
UINFO(4, " INITIAL " << nodep << endl);
|
||||
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||
AstActive* wantactivep = m_namer.getIActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignAlias* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," ASSIGNW "<<nodep<<endl);
|
||||
UINFO(4, " ASSIGNW " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssignW* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," ASSIGNW "<<nodep<<endl);
|
||||
UINFO(4, " ASSIGNW " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCoverToggle* nodep) override {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," COVERTOGGLE "<<nodep<<endl);
|
||||
UINFO(4, " COVERTOGGLE " << nodep << endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFinal* nodep) override {
|
||||
// Relink to CFUNC for the final
|
||||
UINFO(4," FINAL "<<nodep<<endl);
|
||||
UINFO(4, " FINAL " << nodep << endl);
|
||||
if (!nodep->bodysp()) { // Empty, Kill it.
|
||||
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
|
||||
return;
|
||||
}
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||
if (!m_scopeFinalp) {
|
||||
m_scopeFinalp = new AstCFunc(
|
||||
nodep->fileline(), "_final_"+m_namer.scopep()->nameDotless(),
|
||||
m_namer.scopep());
|
||||
nodep->fileline(), "_final_" + m_namer.scopep()->nameDotless(), m_namer.scopep());
|
||||
m_scopeFinalp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
m_scopeFinalp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign() + "\n"));
|
||||
m_scopeFinalp->dontCombine(true);
|
||||
m_scopeFinalp->formCallTree(true);
|
||||
m_scopeFinalp->slow(true);
|
||||
@@ -300,9 +292,7 @@ private:
|
||||
// METHODS
|
||||
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
if (oldsensesp
|
||||
&& oldsensesp->sensesp()
|
||||
&& VN_IS(oldsensesp->sensesp(), SenItem)
|
||||
if (oldsensesp && oldsensesp->sensesp() && VN_IS(oldsensesp->sensesp(), SenItem)
|
||||
&& VN_CAST(oldsensesp->sensesp(), SenItem)->isNever()) {
|
||||
// Never executing. Kill it.
|
||||
UASSERT_OBJ(!oldsensesp->sensesp()->nextp(), nodep,
|
||||
@@ -318,15 +308,14 @@ private:
|
||||
bool combo = m_itemCombo;
|
||||
bool sequent = m_itemSequent;
|
||||
|
||||
if (!combo && !sequent) combo=true; // If no list, Verilog 2000: always @ (*)
|
||||
if (!combo && !sequent) combo = true; // If no list, Verilog 2000: always @ (*)
|
||||
if (combo && sequent) {
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity (no edge) sensitive activity list");
|
||||
}
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Mixed edge (pos/negedge) and activity "
|
||||
"(no edge) sensitive activity list");
|
||||
sequent = false;
|
||||
}
|
||||
|
||||
AstActive* wantactivep = NULL;
|
||||
AstActive* wantactivep = nullptr;
|
||||
if (combo && !sequent) {
|
||||
// Combo: Relink to ACTIVE(combo)
|
||||
wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
@@ -336,8 +325,9 @@ private:
|
||||
// always (posedge RESET) { if (RESET).... } we know RESET is true.
|
||||
// Summarize a long list of combo inputs as just "combo"
|
||||
#ifndef __COVERITY__ // Else dead code on next line.
|
||||
if (combo) oldsensesp->addSensesp
|
||||
(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
|
||||
if (combo) {
|
||||
oldsensesp->addSensesp(new AstSenItem(nodep->fileline(), AstSenItem::Combo()));
|
||||
}
|
||||
#endif
|
||||
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
|
||||
}
|
||||
@@ -354,19 +344,18 @@ private:
|
||||
// Warn and/or convert any delayed assignments
|
||||
if (combo && !sequent) {
|
||||
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_LATCH);
|
||||
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_LATCH);
|
||||
} else {
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_COMBO);
|
||||
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_COMBO);
|
||||
}
|
||||
}
|
||||
else if (!combo && sequent) {
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_SEQ);
|
||||
} else if (!combo && sequent) {
|
||||
ActiveDlyVisitor dlyvisitor(nodep, ActiveDlyVisitor::CT_SEQ);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALW "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
|
||||
UINFO(4, " ALW " << nodep << endl);
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
||||
|
||||
if (!nodep->bodysp()) {
|
||||
// Empty always. Kill it.
|
||||
@@ -375,21 +364,23 @@ private:
|
||||
}
|
||||
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlwaysPublic* nodep) override {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALWPub "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout, " Alw: ");
|
||||
UINFO(4, " ALWPub " << nodep << endl);
|
||||
// if (debug() >= 9) nodep->dumpTree(cout, " Alw: ");
|
||||
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) VL_OVERRIDE {
|
||||
AstSenItem* subitemp = nodep->sensesp();
|
||||
UASSERT_OBJ(subitemp->edgeType() == VEdgeType::ET_ANYEDGE
|
||||
|| subitemp->edgeType() == VEdgeType::ET_POSEDGE
|
||||
|| subitemp->edgeType() == VEdgeType::ET_NEGEDGE,
|
||||
nodep, "Strange activity type under SenGate");
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSenItem* nodep) override {
|
||||
if (nodep->varrefp()) {
|
||||
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
|
||||
if (basicp->isEventValue()) {
|
||||
// Events need to be treated as active high so we only activate on event being
|
||||
// 1
|
||||
UINFO(8, "Demote event to HIGHEDGE " << nodep << endl);
|
||||
nodep->edgeType(VEdgeType::ET_HIGHEDGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) {
|
||||
m_itemCombo = true;
|
||||
// Delete the sensitivity
|
||||
@@ -398,8 +389,9 @@ private:
|
||||
} else if (nodep->varrefp()) {
|
||||
// V3LinkResolve should have cleaned most of these up
|
||||
if (!nodep->varrefp()->width1()) {
|
||||
nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
||||
<<nodep->varrefp()->prettyNameQ());
|
||||
nodep->v3warn(E_UNSUPPORTED,
|
||||
"Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
||||
<< nodep->varrefp()->prettyNameQ());
|
||||
}
|
||||
m_itemSequent = true;
|
||||
nodep->varrefp()->varp()->usedClock(true);
|
||||
@@ -407,28 +399,21 @@ private:
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeMath*) override {} // Accelerate
|
||||
virtual void visit(AstVarScope*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ActiveVisitor(AstNetlist* nodep)
|
||||
: m_scopeFinalp(NULL)
|
||||
, m_itemCombo(false)
|
||||
, m_itemSequent(false) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ActiveVisitor() {}
|
||||
explicit ActiveVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ActiveVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Active class functions
|
||||
|
||||
void V3Active::activeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
ActiveVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ActiveVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+32
-44
@@ -42,35 +42,35 @@ private:
|
||||
// AstNode::user() bool. True if processed
|
||||
// Each call to V3Const::constify
|
||||
// AstNode::user4() Used by V3Const::constify, called below
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstTopScope* m_topscopep; // Top scope for adding sentrees under
|
||||
SenTreeFinder m_finder; // Find global sentree's and add them
|
||||
AstTopScope* m_topscopep = nullptr; // Top scope for adding sentrees under
|
||||
SenTreeFinder m_finder; // Find global sentree's and add them
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstTopScope* nodep) override {
|
||||
m_topscopep = nodep;
|
||||
m_finder.main(m_topscopep);
|
||||
m_finder.init(m_topscopep);
|
||||
iterateChildren(nodep);
|
||||
m_topscopep = NULL;
|
||||
m_topscopep = nullptr;
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
// Create required actives and add to module
|
||||
// We can start ordering at a module, or a scope
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
UINFO(4, " MOD " << nodep << endl);
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstActive* nodep) VL_OVERRIDE {
|
||||
UINFO(4," ACTIVE "<<nodep<<endl);
|
||||
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
|
||||
virtual void visit(AstActive* nodep) override {
|
||||
UINFO(4, " ACTIVE " << nodep << endl);
|
||||
// Remove duplicate clocks and such; sensesp() may change!
|
||||
V3Const::constifyExpensiveEdit(nodep);
|
||||
AstSenTree* sensesp = nodep->sensesp();
|
||||
UASSERT_OBJ(sensesp, nodep, "NULL");
|
||||
if (sensesp->sensesp()
|
||||
&& VN_IS(sensesp->sensesp(), SenItem)
|
||||
UASSERT_OBJ(sensesp, nodep, "nullptr");
|
||||
if (sensesp->sensesp() && VN_IS(sensesp->sensesp(), SenItem)
|
||||
&& VN_CAST(sensesp->sensesp(), SenItem)->isNever()) {
|
||||
// Never executing. Kill it.
|
||||
UASSERT_OBJ(!sensesp->sensesp()->nextp(), nodep,
|
||||
@@ -80,21 +80,20 @@ private:
|
||||
}
|
||||
// Copy combo tree to settlement tree with duplicated statements
|
||||
if (sensesp->hasCombo()) {
|
||||
AstSenTree* newsentreep
|
||||
= new AstSenTree(nodep->fileline(),
|
||||
new AstSenItem(nodep->fileline(), AstSenItem::Settle()));
|
||||
AstActive* newp = new AstActive(nodep->fileline(),"settle", newsentreep);
|
||||
AstSenTree* newsentreep = new AstSenTree(
|
||||
nodep->fileline(), new AstSenItem(nodep->fileline(), AstSenItem::Settle()));
|
||||
AstActive* newp = new AstActive(nodep->fileline(), "settle", newsentreep);
|
||||
newp->sensesStorep(newsentreep);
|
||||
if (nodep->stmtsp()) newp->addStmtsp(nodep->stmtsp()->cloneTree(true));
|
||||
nodep->addNextHere(newp);
|
||||
}
|
||||
// Move the SENTREE for each active up to the global level.
|
||||
// This way we'll easily see what clock domains are identical
|
||||
AstSenTree* wantp = m_finder.getSenTree(nodep->fileline(), sensesp);
|
||||
UINFO(4," lookdone\n");
|
||||
AstSenTree* wantp = m_finder.getSenTree(sensesp);
|
||||
UINFO(4, " lookdone\n");
|
||||
if (wantp != sensesp) {
|
||||
// Move the active's contents to the other active
|
||||
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
|
||||
UINFO(4, " merge active " << sensesp << " into " << wantp << endl);
|
||||
if (nodep->sensesStorep()) {
|
||||
UASSERT_OBJ(sensesp == nodep->sensesStorep(), nodep,
|
||||
"sensesStore should have been deleted earlier if different");
|
||||
@@ -107,47 +106,36 @@ private:
|
||||
nodep->sensesp(wantp);
|
||||
}
|
||||
// No need to do statements under it, they're already moved.
|
||||
//iterateChildren(nodep);
|
||||
// iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstNodeProcedure* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAssignAlias* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAssignW* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
virtual void visit(AstAlwaysPublic* nodep) override { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) VL_OVERRIDE { // LCOV_EXCL_LINE
|
||||
nodep->v3fatalSrc("Node should have been deleted");
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNodeMath*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstVarScope*) VL_OVERRIDE {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNodeMath*) override {} // Accelerate
|
||||
virtual void visit(AstVarScope*) override {} // Accelerate
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit ActiveTopVisitor(AstNetlist* nodep)
|
||||
: m_topscopep(NULL) {
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~ActiveTopVisitor() {}
|
||||
explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~ActiveTopVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Active class functions
|
||||
|
||||
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
ActiveTopVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ ActiveTopVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+93
-103
@@ -23,9 +23,6 @@
|
||||
#include "V3GraphDfa.h"
|
||||
#include "V3Stats.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
|
||||
//######################################################################
|
||||
// Assert class functions
|
||||
|
||||
@@ -34,30 +31,28 @@ private:
|
||||
// NODE STATE/TYPES
|
||||
// Cleared on netlist
|
||||
// AstNode::user() -> bool. True if processed
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstNodeModule* m_modp; // Last module
|
||||
AstBegin* m_beginp; // Last begin
|
||||
unsigned m_modPastNum; // Module past numbering
|
||||
VDouble0 m_statCover; // Statistic tracking
|
||||
VDouble0 m_statAsNotImm; // Statistic tracking
|
||||
VDouble0 m_statAsImm; // Statistic tracking
|
||||
VDouble0 m_statAsFull; // Statistic tracking
|
||||
AstNodeModule* m_modp = nullptr; // Last module
|
||||
AstBegin* m_beginp = nullptr; // Last begin
|
||||
unsigned m_modPastNum = 0; // Module past numbering
|
||||
VDouble0 m_statCover; // Statistic tracking
|
||||
VDouble0 m_statAsNotImm; // Statistic tracking
|
||||
VDouble0 m_statAsImm; // Statistic tracking
|
||||
VDouble0 m_statAsFull; // Statistic tracking
|
||||
|
||||
// METHODS
|
||||
string assertDisplayMessage(AstNode* nodep, const string& prefix, const string& message) {
|
||||
return (string("[%0t] "+prefix+": ")+nodep->fileline()->filebasename()
|
||||
+":"+cvtToStr(nodep->fileline()->lineno())
|
||||
+": Assertion failed in %m"
|
||||
+((message != "")?": ":"")+message
|
||||
+"\n");
|
||||
return (string("[%0t] " + prefix + ": ") + nodep->fileline()->filebasename() + ":"
|
||||
+ cvtToStr(nodep->fileline()->lineno()) + ": Assertion failed in %m"
|
||||
+ ((message != "") ? ": " : "") + message + "\n");
|
||||
}
|
||||
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
||||
nodep->displayType(AstDisplayType::DT_WRITE);
|
||||
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
||||
// cppcheck-suppress nullPointer
|
||||
AstNode* timenewp = new AstTime(nodep->fileline());
|
||||
AstNode* timenewp = new AstTime(nodep->fileline(), m_modp->timeunit());
|
||||
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
|
||||
timesp->unlinkFrBackWithNext();
|
||||
timenewp->addNext(timesp);
|
||||
@@ -77,17 +72,17 @@ private:
|
||||
// If assertions are off, have constant propagation rip them out later
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
(v3Global.opt.assertOn()
|
||||
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
|
||||
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
|
||||
nodep, NULL);
|
||||
? static_cast<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
|
||||
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
|
||||
nodep, nullptr);
|
||||
newp->user1(true); // Don't assert/cover this if
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstNode* newFireAssertUnchecked(AstNode* nodep, const string& message) {
|
||||
// Like newFireAssert() but omits the asserts-on check
|
||||
AstDisplay* dispp = new AstDisplay(nodep->fileline(),
|
||||
AstDisplayType::DT_ERROR, message, NULL, NULL);
|
||||
AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message,
|
||||
nullptr, nullptr);
|
||||
AstNode* bodysp = dispp;
|
||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||
bodysp->addNext(new AstStop(nodep->fileline(), true));
|
||||
@@ -117,9 +112,9 @@ private:
|
||||
sentreep->unlinkFrBack();
|
||||
}
|
||||
//
|
||||
AstNode* bodysp = NULL;
|
||||
AstNode* bodysp = nullptr;
|
||||
bool selfDestruct = false;
|
||||
AstIf* ifp = NULL;
|
||||
AstIf* ifp = nullptr;
|
||||
if (AstCover* snodep = VN_CAST(nodep, Cover)) {
|
||||
++m_statCover;
|
||||
if (!v3Global.opt.coverageUser()) {
|
||||
@@ -129,21 +124,24 @@ private:
|
||||
AstCoverInc* covincp = VN_CAST(snodep->coverincp(), CoverInc);
|
||||
UASSERT_OBJ(covincp, snodep, "Missing AstCoverInc under assertion");
|
||||
covincp->unlinkFrBackWithNext(); // next() might have AstAssign for trace
|
||||
if (message!="") covincp->declp()->comment(message);
|
||||
if (message != "") covincp->declp()->comment(message);
|
||||
bodysp = covincp;
|
||||
}
|
||||
|
||||
if (bodysp && passsp) bodysp = bodysp->addNext(passsp);
|
||||
ifp = new AstIf(nodep->fileline(), propp, bodysp, NULL);
|
||||
ifp = new AstIf(nodep->fileline(), propp, bodysp, nullptr);
|
||||
bodysp = ifp;
|
||||
} else if (VN_IS(nodep, Assert)) {
|
||||
if (nodep->immediate()) ++m_statAsImm;
|
||||
else ++m_statAsNotImm;
|
||||
if (nodep->immediate()) {
|
||||
++m_statAsImm;
|
||||
} else {
|
||||
++m_statAsNotImm;
|
||||
}
|
||||
if (passsp) passsp = newIfAssertOn(passsp);
|
||||
if (failsp) failsp = newIfAssertOn(failsp);
|
||||
if (!failsp) failsp = newFireAssertUnchecked(nodep, "'assert' failed.");
|
||||
ifp = new AstIf(nodep->fileline(), propp, passsp, failsp);
|
||||
// It's more LIKELY that we'll take the NULL if clause
|
||||
// It's more LIKELY that we'll take the nullptr if clause
|
||||
// than the sim-killing else clause:
|
||||
ifp->branchPred(VBranchPred::BP_LIKELY);
|
||||
bodysp = newIfAssertOn(ifp);
|
||||
@@ -153,9 +151,10 @@ private:
|
||||
|
||||
AstNode* newp;
|
||||
if (sentreep) {
|
||||
newp = new AstAlways(nodep->fileline(),
|
||||
VAlwaysKwd::ALWAYS, sentreep, bodysp);
|
||||
} else { newp = bodysp; }
|
||||
newp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, bodysp);
|
||||
} else {
|
||||
newp = bodysp;
|
||||
}
|
||||
// Install it
|
||||
if (selfDestruct) {
|
||||
// Delete it after making the tree. This way we can tell the user
|
||||
@@ -170,11 +169,11 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstIf* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstIf* nodep) override {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
AstNodeIf* ifp = nodep;
|
||||
AstNode* propp = NULL;
|
||||
AstNode* propp = nullptr;
|
||||
bool hasDefaultElse = false;
|
||||
do {
|
||||
// If this statement ends with 'else if', then nextIf will point to the
|
||||
@@ -186,7 +185,7 @@ private:
|
||||
iterateAndNextNull(ifp->ifsp());
|
||||
|
||||
// If the last else is not an else if, recurse into that too.
|
||||
if (ifp->elsesp() && !nextifp) {
|
||||
if (ifp->elsesp() && !nextifp) { //
|
||||
iterateAndNextNull(ifp->elsesp());
|
||||
}
|
||||
|
||||
@@ -199,14 +198,12 @@ private:
|
||||
}
|
||||
|
||||
// Record if this ends with an 'else' that does not have an if
|
||||
if (ifp->elsesp() && !nextifp) {
|
||||
hasDefaultElse = true;
|
||||
}
|
||||
if (ifp->elsesp() && !nextifp) hasDefaultElse = true;
|
||||
|
||||
ifp = nextifp;
|
||||
} while (ifp);
|
||||
|
||||
AstNode *newifp = nodep->cloneTree(false);
|
||||
AstNode* newifp = nodep->cloneTree(false);
|
||||
bool allow_none = nodep->unique0Pragma();
|
||||
|
||||
// Empty case means no property
|
||||
@@ -215,12 +212,11 @@ private:
|
||||
// Note: if this ends with an 'else', then we don't need to validate that one of the
|
||||
// predicates evaluates to true.
|
||||
AstNode* ohot = ((allow_none || hasDefaultElse)
|
||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||
AstIf* checkifp = new AstIf(nodep->fileline(),
|
||||
new AstLogNot(nodep->fileline(), ohot),
|
||||
newFireAssert(nodep, "'unique if' statement violated"),
|
||||
newifp);
|
||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||
AstIf* checkifp
|
||||
= new AstIf(nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
|
||||
newFireAssert(nodep, "'unique if' statement violated"), newifp);
|
||||
checkifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
nodep->replaceWith(checkifp);
|
||||
pushDeletep(nodep);
|
||||
@@ -230,20 +226,21 @@ private:
|
||||
}
|
||||
|
||||
//========== Case assertions
|
||||
virtual void visit(AstCase* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCase* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
bool has_default = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp();
|
||||
itemp; itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
if (itemp->isDefault()) has_default = true;
|
||||
}
|
||||
if (nodep->fullPragma() || nodep->priorityPragma()) {
|
||||
// Simply need to add a default if there isn't one already
|
||||
++m_statAsFull;
|
||||
if (!has_default) {
|
||||
nodep->addItemsp(new AstCaseItem(nodep->fileline(), NULL/*DEFAULT*/,
|
||||
newFireAssert(nodep, "synthesis full_case, but non-match found")));
|
||||
nodep->addItemsp(new AstCaseItem(
|
||||
nodep->fileline(), nullptr /*DEFAULT*/,
|
||||
newFireAssert(nodep, "synthesis full_case, but non-match found")));
|
||||
}
|
||||
}
|
||||
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
@@ -253,7 +250,7 @@ private:
|
||||
if (!has_default && !nodep->itemsp()) {
|
||||
// Not parallel, but harmlessly so.
|
||||
} else {
|
||||
AstNode* propp = NULL;
|
||||
AstNode* propp = nullptr;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
|
||||
itemp = VN_CAST(itemp->nextp(), CaseItem)) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
|
||||
@@ -271,8 +268,11 @@ private:
|
||||
nodep->exprp()->cloneTree(false),
|
||||
icondp->cloneTree(false));
|
||||
}
|
||||
if (propp) propp = new AstConcat(icondp->fileline(), onep, propp);
|
||||
else propp = onep;
|
||||
if (propp) {
|
||||
propp = new AstConcat(icondp->fileline(), onep, propp);
|
||||
} else {
|
||||
propp = onep;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Empty case means no property
|
||||
@@ -281,12 +281,13 @@ private:
|
||||
bool allow_none = has_default || nodep->unique0Pragma();
|
||||
AstNode* ohot
|
||||
= (allow_none
|
||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||
AstIf* ifp = new AstIf(nodep->fileline(),
|
||||
new AstLogNot(nodep->fileline(), ohot),
|
||||
newFireAssert(nodep, "synthesis parallel_case, but multiple matches found"),
|
||||
NULL);
|
||||
? static_cast<AstNode*>(new AstOneHot0(nodep->fileline(), propp))
|
||||
: static_cast<AstNode*>(new AstOneHot(nodep->fileline(), propp)));
|
||||
AstIf* ifp = new AstIf(
|
||||
nodep->fileline(), new AstLogNot(nodep->fileline(), ohot),
|
||||
newFireAssert(nodep,
|
||||
"synthesis parallel_case, but multiple matches found"),
|
||||
nullptr);
|
||||
ifp->branchPred(VBranchPred::BP_UNLIKELY);
|
||||
nodep->addNotParallelp(ifp);
|
||||
}
|
||||
@@ -295,7 +296,7 @@ private:
|
||||
}
|
||||
|
||||
//========== Past
|
||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstPast* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
uint32_t ticks = 1;
|
||||
if (nodep->ticksp()) {
|
||||
@@ -303,95 +304,86 @@ private:
|
||||
"Expected constant ticks, checked in V3Width");
|
||||
ticks = VN_CAST(nodep->ticksp(), Const)->toUInt();
|
||||
}
|
||||
UASSERT_OBJ(ticks>=1, nodep, "0 tick should have been checked in V3Width");
|
||||
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
|
||||
AstNode* inp = nodep->exprp()->unlinkFrBack();
|
||||
AstVar* invarp = NULL;
|
||||
AstSenTree* sentreep = nodep->sentreep(); sentreep->unlinkFrBack();
|
||||
AstAlways* alwaysp = new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS,
|
||||
sentreep, NULL);
|
||||
AstVar* invarp = nullptr;
|
||||
AstSenTree* sentreep = nodep->sentreep();
|
||||
sentreep->unlinkFrBack();
|
||||
AstAlways* alwaysp
|
||||
= new AstAlways(nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr);
|
||||
m_modp->addStmtp(alwaysp);
|
||||
for (uint32_t i=0; i<ticks; ++i) {
|
||||
for (uint32_t i = 0; i < ticks; ++i) {
|
||||
AstVar* outvarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP,
|
||||
"_Vpast_"+cvtToStr(m_modPastNum++)+"_"+cvtToStr(i),
|
||||
"_Vpast_" + cvtToStr(m_modPastNum++) + "_" + cvtToStr(i),
|
||||
inp->dtypep());
|
||||
m_modp->addStmtp(outvarp);
|
||||
AstNode* assp = new AstAssignDly(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), outvarp, true),
|
||||
inp);
|
||||
AstNode* assp = new AstAssignDly(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), outvarp, VAccess::WRITE), inp);
|
||||
alwaysp->addStmtp(assp);
|
||||
//if (debug()>-9) assp->dumpTree(cout, "-ass: ");
|
||||
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
|
||||
invarp = outvarp;
|
||||
inp = new AstVarRef(nodep->fileline(), invarp, false);
|
||||
inp = new AstVarRef(nodep->fileline(), invarp, VAccess::READ);
|
||||
}
|
||||
nodep->replaceWith(inp);
|
||||
}
|
||||
virtual void visit(AstSampled* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstSampled* nodep) override {
|
||||
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
//========== Statements
|
||||
virtual void visit(AstDisplay* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstDisplay* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Replace the special types with standard text
|
||||
if (nodep->displayType()==AstDisplayType::DT_INFO) {
|
||||
if (nodep->displayType() == AstDisplayType::DT_INFO) {
|
||||
replaceDisplay(nodep, "-Info");
|
||||
} else if (nodep->displayType()==AstDisplayType::DT_WARNING) {
|
||||
} else if (nodep->displayType() == AstDisplayType::DT_WARNING) {
|
||||
replaceDisplay(nodep, "%%Warning");
|
||||
} else if (nodep->displayType()==AstDisplayType::DT_ERROR
|
||||
|| nodep->displayType()==AstDisplayType::DT_FATAL) {
|
||||
} else if (nodep->displayType() == AstDisplayType::DT_ERROR
|
||||
|| nodep->displayType() == AstDisplayType::DT_FATAL) {
|
||||
replaceDisplay(nodep, "%%Error");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAssert* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAssert* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, nodep->failsp());
|
||||
}
|
||||
virtual void visit(AstCover* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstCover* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
newPslAssertion(nodep, NULL);
|
||||
newPslAssertion(nodep, nullptr);
|
||||
}
|
||||
virtual void visit(AstRestrict* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRestrict* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// IEEE says simulator ignores these
|
||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
AstNodeModule* origModp = m_modp;
|
||||
unsigned origPastNum = m_modPastNum;
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
VL_RESTORER(m_modp);
|
||||
VL_RESTORER(m_modPastNum);
|
||||
{
|
||||
m_modp = nodep;
|
||||
m_modPastNum = 0;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_modp = origModp;
|
||||
m_modPastNum = origPastNum;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstBegin* nodep) override {
|
||||
// This code is needed rather than a visitor in V3Begin,
|
||||
// because V3Assert is called before V3Begin
|
||||
AstBegin* lastp = m_beginp;
|
||||
VL_RESTORER(m_beginp);
|
||||
{
|
||||
m_beginp = nodep;
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
m_beginp = lastp;
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit AssertVisitor(AstNetlist* nodep) {
|
||||
m_beginp = NULL;
|
||||
m_modp = NULL;
|
||||
m_modPastNum = 0;
|
||||
// Process
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~AssertVisitor() {
|
||||
explicit AssertVisitor(AstNetlist* nodep) { iterate(nodep); }
|
||||
virtual ~AssertVisitor() override {
|
||||
V3Stats::addStat("Assertions, assert non-immediate statements", m_statAsNotImm);
|
||||
V3Stats::addStat("Assertions, assert immediate statements", m_statAsImm);
|
||||
V3Stats::addStat("Assertions, cover statements", m_statCover);
|
||||
@@ -403,9 +395,7 @@ public:
|
||||
// Top Assert class
|
||||
|
||||
void V3Assert::assertAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
AssertVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ AssertVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+95
-44
@@ -23,9 +23,6 @@
|
||||
#include "V3Global.h"
|
||||
#include "V3AssertPre.h"
|
||||
|
||||
#include <cstdarg>
|
||||
#include <iomanip>
|
||||
|
||||
//######################################################################
|
||||
// Assert class functions
|
||||
|
||||
@@ -37,38 +34,41 @@ private:
|
||||
// NODE STATE/TYPES
|
||||
// STATE
|
||||
// Reset each module:
|
||||
AstNodeSenItem* m_seniDefaultp; // Default sensitivity (from AstDefClock)
|
||||
AstSenItem* m_seniDefaultp = nullptr; // Default sensitivity (from AstDefClock)
|
||||
// Reset each assertion:
|
||||
AstNodeSenItem* m_senip; // Last sensitivity
|
||||
AstSenItem* m_senip = nullptr; // Last sensitivity
|
||||
// Reset each always:
|
||||
AstNodeSenItem* m_seniAlwaysp; // Last sensitivity in always
|
||||
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
|
||||
// Reset each assertion:
|
||||
AstNode* m_disablep = nullptr; // Last disable
|
||||
|
||||
// METHODS
|
||||
VL_DEBUG_FUNC; // Declare debug()
|
||||
|
||||
AstSenTree* newSenTree(AstNode* nodep) {
|
||||
// Create sentree based on clocked or default clock
|
||||
// Return NULL for always
|
||||
AstSenTree* newp = NULL;
|
||||
AstNodeSenItem* senip = m_senip;
|
||||
// Return nullptr for always
|
||||
AstSenTree* newp = nullptr;
|
||||
AstSenItem* senip = m_senip;
|
||||
if (!senip) senip = m_seniDefaultp;
|
||||
if (!senip) senip = m_seniAlwaysp;
|
||||
if (!senip) {
|
||||
nodep->v3error("Unsupported: Unclocked assertion");
|
||||
newp = new AstSenTree(nodep->fileline(), NULL);
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion");
|
||||
newp = new AstSenTree(nodep->fileline(), nullptr);
|
||||
} else {
|
||||
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
|
||||
}
|
||||
return newp;
|
||||
}
|
||||
void clearAssertInfo() {
|
||||
m_senip = NULL;
|
||||
m_senip = nullptr;
|
||||
m_disablep = nullptr;
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
//========== Statements
|
||||
virtual void visit(AstClocking* nodep) VL_OVERRIDE {
|
||||
UINFO(8," CLOCKING"<<nodep<<endl);
|
||||
virtual void visit(AstClocking* nodep) override {
|
||||
UINFO(8, " CLOCKING" << nodep << endl);
|
||||
// Store the new default clock, reset on new module
|
||||
m_seniDefaultp = nodep->sensesp();
|
||||
// Trash it, keeping children
|
||||
@@ -79,48 +79,103 @@ private:
|
||||
}
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstAlways* nodep) override {
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
if (nodep->sensesp()) {
|
||||
m_seniAlwaysp = nodep->sensesp()->sensesp();
|
||||
}
|
||||
if (nodep->sensesp()) m_seniAlwaysp = nodep->sensesp()->sensesp();
|
||||
iterateAndNextNull(nodep->bodysp());
|
||||
m_seniAlwaysp = NULL;
|
||||
m_seniAlwaysp = nullptr;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeCoverOrAssert* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeCoverOrAssert* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
clearAssertInfo();
|
||||
// Find Clocking's buried under nodep->exprsp
|
||||
iterateChildren(nodep);
|
||||
if (!nodep->immediate()) {
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
if (!nodep->immediate()) nodep->sentreep(newSenTree(nodep));
|
||||
clearAssertInfo();
|
||||
}
|
||||
virtual void visit(AstPast* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstFell* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstPast* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
}
|
||||
virtual void visit(AstPropClocked* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstRose* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstStable* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
iterateChildren(nodep);
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNode* past = new AstPast(fl, exprp, nullptr);
|
||||
past->dtypeFrom(exprp);
|
||||
exprp = new AstEq(fl, past, exprp->cloneTree(false));
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstImplication* nodep) override {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
|
||||
FileLine* fl = nodep->fileline();
|
||||
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
|
||||
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
|
||||
|
||||
if (m_disablep) { lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp); }
|
||||
|
||||
AstNode* past = new AstPast(fl, lhsp, nullptr);
|
||||
past->dtypeFrom(lhsp);
|
||||
AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
|
||||
exprp->dtypeSetLogicBool();
|
||||
nodep->replaceWith(exprp);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstPropClocked* nodep) override {
|
||||
// No need to iterate the body, once replace will get iterated
|
||||
iterateAndNextNull(nodep->sensesp());
|
||||
if (m_senip) {
|
||||
nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
|
||||
}
|
||||
if (m_senip)
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
|
||||
// Block is the new expression to evaluate
|
||||
AstNode* blockp = nodep->propp()->unlinkFrBack();
|
||||
if (nodep->disablep()) {
|
||||
m_disablep = nodep->disablep()->cloneTree(false);
|
||||
if (VN_IS(nodep->backp(), Cover)) {
|
||||
blockp = new AstAnd(nodep->disablep()->fileline(),
|
||||
new AstNot(nodep->disablep()->fileline(),
|
||||
nodep->disablep()->unlinkFrBack()),
|
||||
blockp);
|
||||
blockp = new AstAnd(
|
||||
nodep->disablep()->fileline(),
|
||||
new AstNot(nodep->disablep()->fileline(), nodep->disablep()->unlinkFrBack()),
|
||||
blockp);
|
||||
} else {
|
||||
blockp = new AstOr(nodep->disablep()->fileline(),
|
||||
nodep->disablep()->unlinkFrBack(),
|
||||
blockp);
|
||||
nodep->disablep()->unlinkFrBack(), blockp);
|
||||
}
|
||||
}
|
||||
// Unlink and just keep a pointer to it, convert to sentree as needed
|
||||
@@ -128,32 +183,28 @@ private:
|
||||
nodep->replaceWith(blockp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
}
|
||||
virtual void visit(AstNodeModule* nodep) VL_OVERRIDE {
|
||||
virtual void visit(AstNodeModule* nodep) override {
|
||||
iterateChildren(nodep);
|
||||
// Reset defaults
|
||||
m_seniDefaultp = NULL;
|
||||
m_seniDefaultp = nullptr;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) VL_OVERRIDE { iterateChildren(nodep); }
|
||||
virtual void visit(AstNode* nodep) override { iterateChildren(nodep); }
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit AssertPreVisitor(AstNetlist* nodep) {
|
||||
m_seniDefaultp = NULL;
|
||||
m_seniAlwaysp = NULL;
|
||||
clearAssertInfo();
|
||||
// Process
|
||||
iterate(nodep);
|
||||
}
|
||||
virtual ~AssertPreVisitor() {}
|
||||
virtual ~AssertPreVisitor() override {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Top Assert class
|
||||
|
||||
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
{
|
||||
AssertPreVisitor visitor (nodep);
|
||||
} // Destruct before checking
|
||||
UINFO(2, __FUNCTION__ << ": " << endl);
|
||||
{ AssertPreVisitor visitor(nodep); } // Destruct before checking
|
||||
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user