mirror of
https://github.com/verilator/verilator.git
synced 2026-10-05 09:33:41 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
379177d2f4 | ||
|
|
fb193d6172 | ||
|
|
16234bb713 | ||
|
|
3f14e649b5 | ||
|
|
c2e8062f84 | ||
|
|
5d3fef21b0 | ||
|
|
b64e1b4a49 | ||
|
|
89f414b185 | ||
|
|
47e13cfdf4 | ||
|
|
48d3ce46d8 | ||
|
|
89c8449ec0 | ||
|
|
331fcb633e | ||
|
|
bffc2233a0 | ||
|
|
393b5d48b2 | ||
|
|
6006cdff2c | ||
|
|
d6b10465f3 | ||
|
|
b3cf5c4f5f | ||
|
|
3862f2f022 | ||
|
|
38ab22bf1d | ||
|
|
ce16f7689d | ||
|
|
b06a329466 | ||
|
|
c5b24f3850 | ||
|
|
103b956581 | ||
|
|
63361fc56e | ||
|
|
1e9e334929 | ||
|
|
f30d71b0c5 | ||
|
|
fee4aba9ec | ||
|
|
f1960273a0 | ||
|
|
778564e63b | ||
|
|
cf6a69da27 | ||
|
|
960b2ed023 | ||
|
|
74420550e6 | ||
|
|
cb5887b376 | ||
|
|
41b40157d8 | ||
|
|
b11b693c08 | ||
|
|
256eb4bba0 | ||
|
|
77804b4d38 | ||
|
|
8c9ca7a1b3 | ||
|
|
9d055f8c13 | ||
|
|
3dacd87dfb | ||
|
|
691fbb0c42 | ||
|
|
c28a6eef3b | ||
|
|
17fed3fedd | ||
|
|
1448cc56fc | ||
|
|
074689b5de | ||
|
|
8dd612a0a0 | ||
|
|
22fdbba0b5 | ||
|
|
39b787670b | ||
|
|
a221278c05 | ||
|
|
5f26b9ec66 | ||
|
|
48778d0a77 | ||
|
|
42d2cbad41 | ||
|
|
cb82c42e35 | ||
|
|
f13fb330ed | ||
|
|
d4bae48ca2 | ||
|
|
590ad964b1 | ||
|
|
d4595df8a4 | ||
|
|
7b642bcbb4 | ||
|
|
ca26596695 | ||
|
|
88cf5e5d98 | ||
|
|
13f790360d | ||
|
|
70daadf987 | ||
|
|
9d5004db1c | ||
|
|
ea82bfcced | ||
|
|
00a502942e | ||
|
|
2031bc7fc4 | ||
|
|
3adb22e971 | ||
|
|
331ea5116f | ||
|
|
1da5a33f88 | ||
|
|
6c87724af8 | ||
|
|
c7a5ff5e82 | ||
|
|
abf2fcf820 | ||
|
|
644c22b08f | ||
|
|
c54024a5e6 | ||
|
|
97093fdf81 | ||
|
|
50c4f60c68 | ||
|
|
f0fb3b78d1 | ||
|
|
9b06178f35 | ||
|
|
a01c96140b | ||
|
|
02530172e7 | ||
|
|
447d803800 | ||
|
|
6b04901c4d | ||
|
|
7fb29621c3 | ||
|
|
b032fce962 | ||
|
|
ce879122bb | ||
|
|
2fa16708b7 | ||
|
|
54bc8608e3 | ||
|
|
706a7802cc | ||
|
|
9dc01cf540 | ||
|
|
8943ad5966 | ||
|
|
deb7a1c9c0 | ||
|
|
96a5445d44 | ||
|
|
d693065afb | ||
|
|
bdeee35669 | ||
|
|
62b3deb90d | ||
|
|
9df9ff59e0 | ||
|
|
23a3271c06 | ||
|
|
f4a5aa2e94 | ||
|
|
bdd54eed1c | ||
|
|
c6a20a72f2 | ||
|
|
d7a54b3632 | ||
|
|
be6a3d0f10 | ||
|
|
e9125a3a22 | ||
|
|
c27a60658f | ||
|
|
8f2bc6e028 | ||
|
|
a6b78cbbee | ||
|
|
182a7076fd | ||
|
|
17a9b22dce | ||
|
|
f190d12802 | ||
|
|
b12dd526f9 | ||
|
|
473d555dc1 | ||
|
|
fa9208ccdd | ||
|
|
4aa088eb2f | ||
|
|
8f8147d646 | ||
|
|
e637dd2390 | ||
|
|
c90960fc88 | ||
|
|
da86a1c9f2 | ||
|
|
0adb789238 | ||
|
|
15082a178b | ||
|
|
4a0db26c36 | ||
|
|
ad3ea636d5 | ||
|
|
6a238b0514 | ||
|
|
e6d7e7e329 | ||
|
|
f942aba855 | ||
|
|
2f34132275 | ||
|
|
663b2be065 | ||
|
|
a1e4d676c3 | ||
|
|
6f28d21207 | ||
|
|
9f115e056e | ||
|
|
8352ba4af4 | ||
|
|
9b06310cbe | ||
|
|
77fe33e57f | ||
|
|
df58eb9bc7 | ||
|
|
2d0084308d | ||
|
|
7efa40966a | ||
|
|
6d644dc764 | ||
|
|
b0de0b1176 | ||
|
|
c72d473e96 | ||
|
|
c8a91bd46f | ||
|
|
498f19a6a1 | ||
|
|
c7a2138ece | ||
|
|
4078902543 | ||
|
|
9e38ed9a39 | ||
|
|
183cabc77d | ||
|
|
b582e481c6 | ||
|
|
ad39931e87 | ||
|
|
1ae22e1365 | ||
|
|
b748ddfe06 | ||
|
|
e52f5f1b63 | ||
|
|
bda4b326ab | ||
|
|
70ddf32719 | ||
|
|
3edba7b662 | ||
|
|
f74ef650ac | ||
|
|
f093c3d78b | ||
|
|
d933f33bdb | ||
|
|
813d62005d | ||
|
|
411de9bddf | ||
|
|
bd28945374 | ||
|
|
1e4c3751e1 | ||
|
|
5b6f47cd0f | ||
|
|
bec8c5bf4c | ||
|
|
15495bb200 | ||
|
|
999f278971 | ||
|
|
7ca1d35a4e | ||
|
|
2117fe414e | ||
|
|
7d8c51181d | ||
|
|
c30211cb27 | ||
|
|
901da118e5 | ||
|
|
f11757e43a | ||
|
|
3f143317a6 | ||
|
|
45d7312dfc | ||
|
|
26774eb045 | ||
|
|
6789d247e2 | ||
|
|
462bc3d707 | ||
|
|
e1755ea6a8 | ||
|
|
b4a7e4697e | ||
|
|
cd61b1d045 | ||
|
|
24dc36ba4c | ||
|
|
e8e4f1777d | ||
|
|
ae38a26af3 | ||
|
|
8ee94dd7aa | ||
|
|
e741a29d36 | ||
|
|
be1d275151 | ||
|
|
31c9e26e2e | ||
|
|
20ed1ada03 | ||
|
|
891214fa72 | ||
|
|
e819e285e2 | ||
|
|
171c175e54 | ||
|
|
675cbce8cb | ||
|
|
4f1398f773 | ||
|
|
ae89e399a3 | ||
|
|
2c9716c64c | ||
|
|
bc58245abf | ||
|
|
8c4aa8517e | ||
|
|
c0b7a54bb9 | ||
|
|
6b32bb635d | ||
|
|
691de22ae3 | ||
|
|
e64b2d3372 | ||
|
|
e190af9d87 | ||
|
|
8d14463b18 | ||
|
|
04977ef721 | ||
|
|
d84e6875c5 | ||
|
|
80678ae7bc | ||
|
|
482bdab0e0 | ||
|
|
b2623b9841 | ||
|
|
9ae40d64f0 | ||
|
|
cef097b7b7 | ||
|
|
b840334ad2 | ||
|
|
acff683e8e | ||
|
|
c5332de86d | ||
|
|
90ecf14a0a | ||
|
|
4945282369 | ||
|
|
ca532d23f0 | ||
|
|
a509b6a21c | ||
|
|
46229473cb | ||
|
|
65be2448dc | ||
|
|
be74806044 | ||
|
|
b488666c1e | ||
|
|
d1acaea611 | ||
|
|
db6e5ce7cf | ||
|
|
d56179df17 | ||
|
|
850100c9c2 | ||
|
|
0725999f0a | ||
|
|
cb2d8259f2 | ||
|
|
61a1f3d817 | ||
|
|
63f111b7f3 | ||
|
|
e061eb3003 | ||
|
|
29daa58222 | ||
|
|
340cc02171 | ||
|
|
b738d1960a | ||
|
|
38f5b780d7 | ||
|
|
fa9dac29e8 | ||
|
|
afc432042f | ||
|
|
21cb29baf0 | ||
|
|
e8b5001cfe | ||
|
|
849c1e46a2 | ||
|
|
ebad6cde36 | ||
|
|
f920b3945e | ||
|
|
178028a70a | ||
|
|
5e54d3e41a | ||
|
|
f0af8726e3 | ||
|
|
57f2fe77ea | ||
|
|
d56ca25089 | ||
|
|
d39ce17dea | ||
|
|
373a68ec8b | ||
|
|
5613758ee3 | ||
|
|
2102f86909 | ||
|
|
d5ea785de7 | ||
|
|
9edd28d2ed | ||
|
|
7698af5178 | ||
|
|
52ae451f5c | ||
|
|
9254443cd4 | ||
|
|
4e4bc7b90f | ||
|
|
c7e0f2e196 | ||
|
|
acabaab6ac | ||
|
|
b0a249f338 | ||
|
|
0cb5d5cc5a | ||
|
|
9208c87f91 | ||
|
|
0081ce4a75 | ||
|
|
7850f49963 | ||
|
|
c72ee41142 | ||
|
|
bf5dee955d | ||
|
|
3df23a148a | ||
|
|
0a1b55c296 | ||
|
|
14b8efe4bb | ||
|
|
64162efebd | ||
|
|
faf5e1de51 | ||
|
|
0d7b1a7dc7 | ||
|
|
fa63bc6b78 | ||
|
|
379bfd062f | ||
|
|
49108c23f0 | ||
|
|
4475060268 | ||
|
|
4f269e336d | ||
|
|
4464b13163 | ||
|
|
215d5f68b0 | ||
|
|
281f4e04ee | ||
|
|
17a3f9691d | ||
|
|
4fde6ee7af | ||
|
|
040b1b06d5 | ||
|
|
b16ea8b719 | ||
|
|
cc22847bc3 | ||
|
|
3702e17b2e | ||
|
|
7abc220fb3 | ||
|
|
4fc9a906f6 | ||
|
|
5de83c9805 | ||
|
|
f71d904a9b | ||
|
|
318ded4198 | ||
|
|
f1874b211f | ||
|
|
c60ffd7fd9 | ||
|
|
dc57282168 | ||
|
|
3c336e179f | ||
|
|
6bda57da5d | ||
|
|
9a16001e51 | ||
|
|
34870e899f | ||
|
|
d0653f72e2 | ||
|
|
64748b7b1d | ||
|
|
7163c8d048 | ||
|
|
d0ec991bb2 | ||
|
|
d458af4454 | ||
|
|
9e9e7c33ae | ||
|
|
ce7de5ed30 | ||
|
|
776d8edf52 | ||
|
|
5f21385e41 | ||
|
|
94fed93f54 | ||
|
|
a950e4816d | ||
|
|
c87c66efb1 | ||
|
|
5a5a0006fe | ||
|
|
60b48a6830 | ||
|
|
5e41350588 | ||
|
|
ff9f5b62ac | ||
|
|
882913f0ca | ||
|
|
2062f7e97b | ||
|
|
445c83a60d | ||
|
|
1891cfd79a | ||
|
|
06d5a7b2bf | ||
|
|
5af8a8aa4c | ||
|
|
dc6b085d8b | ||
|
|
00759f777e | ||
|
|
95ac0e61b2 | ||
|
|
6c5884853f | ||
|
|
7578ef889f | ||
|
|
da254af8d5 | ||
|
|
98123dc422 | ||
|
|
466909b3d9 | ||
|
|
0d4305192a | ||
|
|
9e61b9f696 | ||
|
|
491539ff32 | ||
|
|
4c29a13a6e | ||
|
|
b66e1bdb9e | ||
|
|
7312de6bc2 | ||
|
|
1d6bcda014 | ||
|
|
5a747bad7d | ||
|
|
9542783a7e | ||
|
|
a59639413d | ||
|
|
d5eb92a071 | ||
|
|
994cde57af | ||
|
|
238a5809bf | ||
|
|
49fa65c0dd | ||
|
|
49123f169c | ||
|
|
4dc64c387f | ||
|
|
98a63711dd | ||
|
|
cb95cf4745 | ||
|
|
acd48fa61d | ||
|
|
cb7abcbaea | ||
|
|
793c974480 | ||
|
|
78a321925f | ||
|
|
643572595e | ||
|
|
fb4d462325 | ||
|
|
c0df07c86f | ||
|
|
e918d945f2 | ||
|
|
0ee5743853 | ||
|
|
486d69da5f | ||
|
|
005b4b7609 | ||
|
|
a0fd065dcf | ||
|
|
751384cb5c | ||
|
|
6ac672b4a3 | ||
|
|
a89502be9f | ||
|
|
04e7b3bd4d | ||
|
|
9ebb37b6a5 | ||
|
|
052a7e3deb | ||
|
|
108c0f6bb8 | ||
|
|
6ed89b6ca5 | ||
|
|
27ccaffb37 | ||
|
|
a001babad2 | ||
|
|
32a76c5255 | ||
|
|
099f797975 | ||
|
|
b7df3e24b4 | ||
|
|
8323092a0c | ||
|
|
e5af46d3fb | ||
|
|
a6743588b6 | ||
|
|
90cbcd2dfd | ||
|
|
a36b7afba5 | ||
|
|
4c91ade61d | ||
|
|
f2a17b9b70 | ||
|
|
b71b9ccb57 | ||
|
|
8b0af19351 | ||
|
|
9f7c473376 | ||
|
|
0206767478 | ||
|
|
1a3378e0f5 | ||
|
|
5c3eee34a1 | ||
|
|
2b5017e610 | ||
|
|
e755c7fdcc | ||
|
|
8d463b33cd | ||
|
|
7d9b21a874 | ||
|
|
a118921b21 | ||
|
|
a1aefd2330 | ||
|
|
8b511379ac | ||
|
|
c1593f856d | ||
|
|
93f1d7643d | ||
|
|
ce4dfb4296 | ||
|
|
2e5f5010f7 | ||
|
|
7c588c2e30 | ||
|
|
43be4cf2b5 | ||
|
|
8b457b9b66 | ||
|
|
25efee2e62 | ||
|
|
546c91a940 | ||
|
|
85ebc5f7bd | ||
|
|
e002b0e25f | ||
|
|
4944383769 | ||
|
|
68c6f0ff07 | ||
|
|
5078152292 | ||
|
|
9837b40330 | ||
|
|
cb645c9a74 | ||
|
|
87573a9fef | ||
|
|
7c486e27ba | ||
|
|
4a3bdc340d | ||
|
|
903ee0622d | ||
|
|
d33ad7600b | ||
|
|
9ec35a2348 | ||
|
|
6da13c6486 | ||
|
|
87a47a5ca0 | ||
|
|
c682f1c16a | ||
|
|
591075a8ed | ||
|
|
41701673a0 | ||
|
|
55f0d4ddd8 | ||
|
|
6d66fcaa57 | ||
|
|
26e79ca889 | ||
|
|
62eb247c1e | ||
|
|
c5fd583b2c | ||
|
|
117db3e11c | ||
|
|
3f82fd2f37 | ||
|
|
e9c46afcf7 | ||
|
|
3234fa15ef | ||
|
|
7ef84df852 | ||
|
|
4e2884b509 | ||
|
|
03100020ab | ||
|
|
8bfb5cc5e9 | ||
|
|
cf6d07aafa | ||
|
|
85c3179dbd | ||
|
|
bfbca34eb0 | ||
|
|
b73edc0564 | ||
|
|
6ba90e3a50 | ||
|
|
e8edbad18c | ||
|
|
c86fec5307 | ||
|
|
6e476255ca | ||
|
|
27af9b6b06 | ||
|
|
f8208fa961 | ||
|
|
87b9cb49ad | ||
|
|
b2da0772e6 | ||
|
|
4f73e0850e | ||
|
|
b6a39db627 | ||
|
|
3a83b06572 | ||
|
|
fe5bf01b25 | ||
|
|
5559ec903b | ||
|
|
18750028b2 | ||
|
|
6b88648c67 | ||
|
|
58ee803cb4 | ||
|
|
894ff73c7d | ||
|
|
8031f0ed7f | ||
|
|
3a56b5da47 | ||
|
|
fedcb6d26a | ||
|
|
eed3c5e543 | ||
|
|
e26ab67e25 | ||
|
|
e77b7427b4 | ||
|
|
475e4207cc | ||
|
|
71b2eed32c | ||
|
|
6cf50e6579 | ||
|
|
69468708e2 | ||
|
|
5da5678e64 | ||
|
|
a428e7f618 | ||
|
|
0eb5a0a539 | ||
|
|
a1c1ff9981 | ||
|
|
2029ade18c | ||
|
|
5f8f474c0c | ||
|
|
f705f9b275 | ||
|
|
91e706ec1f | ||
|
|
dcf351f847 | ||
|
|
06744b664a | ||
|
|
d3049d9c89 | ||
|
|
1f2abb9c0f | ||
|
|
9f0d7e50a5 | ||
|
|
5f262a8f11 | ||
|
|
f62bc6a2e5 | ||
|
|
d7e4bc1379 | ||
|
|
cd2d6575c6 | ||
|
|
b46f656d17 | ||
|
|
58fd602bbd | ||
|
|
9cc95704cd | ||
|
|
5f5a3dbb0a | ||
|
|
f8f53df4ec | ||
|
|
56b85cc63c | ||
|
|
90aca97e66 | ||
|
|
6ce2a52c5f | ||
|
|
1f56312132 | ||
|
|
3aa290cddb | ||
|
|
1d1eb4fedb | ||
|
|
266ff41386 | ||
|
|
02331e5536 | ||
|
|
621c51589a | ||
|
|
4a58e859a4 | ||
|
|
48d393d8f5 | ||
|
|
321552d998 | ||
|
|
a985a1f9f5 | ||
|
|
d532a36739 | ||
|
|
b631b5927b | ||
|
|
adb39ceb98 | ||
|
|
84b91b19ca | ||
|
|
aaea68d3d6 | ||
|
|
2accba2e71 | ||
|
|
8f4f4eb5ae | ||
|
|
c5aabb3c6e | ||
|
|
60c2d136e1 | ||
|
|
cae6ec16ba | ||
|
|
30601c77d4 | ||
|
|
b0f4cf3c9c | ||
|
|
c41dfcf6ad | ||
|
|
2e10555f03 | ||
|
|
6b2ee0fcf3 | ||
|
|
0dbdbffba7 | ||
|
|
9c5dd8d767 | ||
|
|
fff0ebb5f3 | ||
|
|
d34275150c | ||
|
|
d04eb977c2 | ||
|
|
fb4928b2f5 | ||
|
|
5c39420d91 | ||
|
|
14fcfd8a40 | ||
|
|
ff19dd94f9 | ||
|
|
b6913ff9b3 | ||
|
|
4573fd3069 | ||
|
|
6cf6d9f7e1 | ||
|
|
28e35a64ea | ||
|
|
091818483a | ||
|
|
3b43556c41 | ||
|
|
ed39c66715 | ||
|
|
446b0e4e5e | ||
|
|
6e3e8318d0 | ||
|
|
17b8b660f0 | ||
|
|
40bceea68a | ||
|
|
b655c17c09 | ||
|
|
a3813f94fc | ||
|
|
c70540a825 | ||
|
|
9caffe330b | ||
|
|
8d8c5da812 | ||
|
|
55bb766c15 | ||
|
|
c18df68ead | ||
|
|
3996e94c39 | ||
|
|
1bdf017f9e | ||
|
|
93790c1dc6 | ||
|
|
ba8c11b25d | ||
|
|
ca57edfa0b | ||
|
|
ccb6545c32 | ||
|
|
d146dbc9d7 | ||
|
|
b4eaaccc88 | ||
|
|
c9ed9e74f2 | ||
|
|
587c7c70f5 | ||
|
|
749ff021b6 | ||
|
|
85c5765c00 | ||
|
|
9e76078939 | ||
|
|
334e0e1ca6 | ||
|
|
dce4519995 | ||
|
|
45bbae80e7 | ||
|
|
d37709a922 | ||
|
|
2560ae9bc1 | ||
|
|
2bdd3ca353 | ||
|
|
8a8aab1aae | ||
|
|
85d790ff79 | ||
|
|
68afc96a9f | ||
|
|
94efaa7675 | ||
|
|
180af74a50 | ||
|
|
88af0d3509 | ||
|
|
97633f7bed | ||
|
|
053e016388 | ||
|
|
2d61e0270e | ||
|
|
3a23afb0bc | ||
|
|
470f12ff46 | ||
|
|
4422de0c6c | ||
|
|
8a708f52f7 | ||
|
|
bcefc17631 | ||
|
|
daf19e241e | ||
|
|
b5f5b1fdf9 | ||
|
|
801b718953 | ||
|
|
f571658aa4 | ||
|
|
5d233b8c09 | ||
|
|
00724597f4 | ||
|
|
c659940ea8 | ||
|
|
23539eb55c | ||
|
|
e69bf418de | ||
|
|
0e1fcd38bb | ||
|
|
e74186565d | ||
|
|
7e54281e26 | ||
|
|
15f512bdee | ||
|
|
ecfe0283e2 | ||
|
|
3b874f759c | ||
|
|
9c9b4ed4e0 | ||
|
|
4f6d80c602 | ||
|
|
b50542531d | ||
|
|
8ab28d1d12 | ||
|
|
9567da22f8 | ||
|
|
36814b7681 | ||
|
|
82235e6c6f | ||
|
|
a8310f35f2 | ||
|
|
85989af031 | ||
|
|
cf9ffd16dd | ||
|
|
0602537cce | ||
|
|
24e32420b7 | ||
|
|
39c494260b | ||
|
|
761b9c9290 | ||
|
|
27686d8c2f | ||
|
|
d2b007005d | ||
|
|
f1ef30a5bb | ||
|
|
f1d9437c55 | ||
|
|
bcba5075e8 | ||
|
|
d6e8b0263c | ||
|
|
9aba617bad | ||
|
|
c24f7b1391 | ||
|
|
d4e27b635f | ||
|
|
c996d2870c | ||
|
|
bbd59f8a22 | ||
|
|
d3d359e757 | ||
|
|
ae763ea93d | ||
|
|
236b9e9761 | ||
|
|
e42c9dfd84 | ||
|
|
bebf5b291b | ||
|
|
1e3dcd203d | ||
|
|
cc7da63dec | ||
|
|
1baa2a2558 | ||
|
|
e63ff77b15 | ||
|
|
6cf9468477 | ||
|
|
b277bc8750 | ||
|
|
ba9da64207 | ||
|
|
9cb9f9c80b | ||
|
|
7a65df7636 | ||
|
|
eab46d547d | ||
|
|
3dd552c4a2 | ||
|
|
23bb045a72 | ||
|
|
7c834ad118 | ||
|
|
8e2617ab8d | ||
|
|
24fcae4f49 | ||
|
|
ce18674d88 | ||
|
|
6b8d9b5c36 | ||
|
|
81bf95763c | ||
|
|
2d64077fd0 | ||
|
|
38faebcf20 | ||
|
|
48d177a9d0 | ||
|
|
3b3a7f7354 | ||
|
|
99cd2818a1 | ||
|
|
5765e099a6 | ||
|
|
175d59ecba | ||
|
|
3bd3d01968 | ||
|
|
85e2a6bb45 | ||
|
|
84efd239a5 | ||
|
|
6a69813326 | ||
|
|
2c9dcc3913 | ||
|
|
20ea1ca018 | ||
|
|
0abde90933 | ||
|
|
e01b69198a | ||
|
|
53cd9d2403 | ||
|
|
3d0f5fc078 | ||
|
|
54eedcc739 | ||
|
|
ae6f5844da | ||
|
|
1bea845ceb | ||
|
|
d581582339 | ||
|
|
4eabc1992e | ||
|
|
316eb24bbb | ||
|
|
f0a8824efc | ||
|
|
345a5d5646 | ||
|
|
464679c78b | ||
|
|
28eeec1cf4 | ||
|
|
7d0dce3267 | ||
|
|
9e29625207 | ||
|
|
a767da4f3f | ||
|
|
7bd96c2876 | ||
|
|
70fd64dcd6 | ||
|
|
bb2822f4b5 | ||
|
|
ad21108b63 | ||
|
|
e6808a787c | ||
|
|
1fb2762725 | ||
|
|
cce55941d3 | ||
|
|
6c8d95e0e2 | ||
|
|
216a178b28 | ||
|
|
6594a54a95 | ||
|
|
a9a4cf061a | ||
|
|
b7f0e204cb | ||
|
|
e6a15f233b | ||
|
|
e0edb596ea | ||
|
|
f2fb77c15a | ||
|
|
772a3a97eb | ||
|
|
6c310836a1 | ||
|
|
75416a3016 | ||
|
|
ebef78a13e | ||
|
|
e71baca39b | ||
|
|
18eb210313 | ||
|
|
7d38a5e1f9 | ||
|
|
4386077e2d | ||
|
|
49dbfd2131 | ||
|
|
a80fce5ac1 | ||
|
|
891b981cab | ||
|
|
2dd87b8384 | ||
|
|
062eb85075 | ||
|
|
e1f6802f5f | ||
|
|
6cfcd50f12 | ||
|
|
bcadb0b3b3 | ||
|
|
0df561f873 | ||
|
|
238fc24684 | ||
|
|
936855c81c | ||
|
|
61ad9d4651 | ||
|
|
f07f6a26a8 | ||
|
|
4a5a56f8ef | ||
|
|
7d44bba95c | ||
|
|
6e6f1045b8 | ||
|
|
5dd3221759 | ||
|
|
09edb467f6 | ||
|
|
ffb187ae15 | ||
|
|
b4a8be07f3 | ||
|
|
4968a2abc5 | ||
|
|
91159da30d | ||
|
|
c9ad61b4fb | ||
|
|
3f0dcd8c0e | ||
|
|
e1eb41fe77 | ||
|
|
498ab23355 | ||
|
|
5d6a053f98 | ||
|
|
929aeebf12 | ||
|
|
00bd947385 | ||
|
|
d4ef86afc0 | ||
|
|
1856cad816 | ||
|
|
91e2d1d2a0 | ||
|
|
f29f30dce0 | ||
|
|
e7ba6ef492 | ||
|
|
de4016dcff | ||
|
|
bbeb382cbb | ||
|
|
385c166830 | ||
|
|
410e6ff203 | ||
|
|
8b47c4e307 | ||
|
|
6d1b42bedb | ||
|
|
f0a4bd28b6 | ||
|
|
2879684f21 | ||
|
|
0437d0abea | ||
|
|
0286f588bf | ||
|
|
042fb76837 | ||
|
|
795e66eac9 | ||
|
|
aae0615ffd | ||
|
|
8127a79cb1 | ||
|
|
057ca497dd | ||
|
|
66b1611649 | ||
|
|
7f5220a6ca | ||
|
|
e41e26717b | ||
|
|
7a8184d206 | ||
|
|
13bf2f19ac | ||
|
|
1d5ebfd0b1 | ||
|
|
dfc11da2ce | ||
|
|
191af2e87b | ||
|
|
0985b82760 | ||
|
|
26f4b5a69a | ||
|
|
5c7a6e278f | ||
|
|
ae1ab8aaaa | ||
|
|
18c25d1b6f | ||
|
|
5888a2c399 | ||
|
|
c00603704e | ||
|
|
786bc4b04f | ||
|
|
5eca20f849 | ||
|
|
0a3a582949 | ||
|
|
08fec0534d | ||
|
|
5bf92c9d3a | ||
|
|
a8bbf7231b | ||
|
|
83c171012d | ||
|
|
229d854607 | ||
|
|
562460606f | ||
|
|
46f70b1cbb | ||
|
|
a547133efe | ||
|
|
cf445898ce | ||
|
|
98f68e46d6 | ||
|
|
27660b271d | ||
|
|
895e374860 | ||
|
|
4c7f051247 | ||
|
|
e68afa53a8 | ||
|
|
cc47ba2404 | ||
|
|
2238fa46ed | ||
|
|
de8b040e31 | ||
|
|
4ffc48d194 | ||
|
|
2433848408 | ||
|
|
e602f7febc | ||
|
|
f607b32938 | ||
|
|
c7a088faa5 | ||
|
|
30f6c0e105 | ||
|
|
38b9fa7b93 | ||
|
|
39a31fc17f | ||
|
|
899a7df14a | ||
|
|
7a8c425103 | ||
|
|
0e8ce59022 | ||
|
|
77ac76a158 | ||
|
|
8108b97050 | ||
|
|
a1c3491dea | ||
|
|
8bba96a84e | ||
|
|
6cd9b25a53 | ||
|
|
0431b1909c | ||
|
|
907665e2e8 | ||
|
|
61e8836fbd | ||
|
|
0e921b5dff | ||
|
|
7ef37d6e17 | ||
|
|
dce227684a | ||
|
|
158e112752 | ||
|
|
ec992c7f5e | ||
|
|
e7d63c7644 | ||
|
|
6464e8fee6 | ||
|
|
047d66a657 | ||
|
|
55c23360d9 | ||
|
|
c378d32c85 | ||
|
|
3d9540c58c | ||
|
|
39724eb916 | ||
|
|
48dddd4ae7 | ||
|
|
9c00fd10de | ||
|
|
9309d0b00f | ||
|
|
038b5d32a3 | ||
|
|
706920ba19 | ||
|
|
39492a0726 | ||
|
|
df1170fea9 | ||
|
|
f0e1d204fa | ||
|
|
8ece0a8a5f | ||
|
|
1373b81e7c | ||
|
|
d3601dd561 | ||
|
|
f685cf1d0c | ||
|
|
d5fcf0c153 | ||
|
|
5f9810070d | ||
|
|
923efa004b | ||
|
|
869e8eab3c | ||
|
|
b51d197117 | ||
|
|
e4f0a8952c | ||
|
|
072ee425f4 | ||
|
|
a4c2819be2 | ||
|
|
2a274f9c19 | ||
|
|
b4d5a20670 | ||
|
|
6339159b04 | ||
|
|
aec019991c | ||
|
|
33e6a17747 | ||
|
|
ecf508ec23 | ||
|
|
a5bcfc0509 | ||
|
|
1899096ff4 | ||
|
|
6e219f5831 | ||
|
|
de1bb5aeb6 | ||
|
|
b52d94273c | ||
|
|
e655c85489 | ||
|
|
dee7210231 | ||
|
|
cbd073ed08 | ||
|
|
09ebc0c163 | ||
|
|
d2ede75c71 | ||
|
|
3e03fef3e3 | ||
|
|
0f583f4b33 | ||
|
|
f175db74a5 | ||
|
|
8d5e37a413 | ||
|
|
8b9b7178a2 | ||
|
|
a2f49063e2 | ||
|
|
f3f34baa73 | ||
|
|
abe9ecd225 | ||
|
|
67409af38d | ||
|
|
b7d1c34aa6 | ||
|
|
92809b95c9 | ||
|
|
b18690cbe2 | ||
|
|
96155365b2 | ||
|
|
3e5067feb1 | ||
|
|
3ec687a0cf | ||
|
|
365034d7dd | ||
|
|
09aa9f87d8 | ||
|
|
97963fb8c9 | ||
|
|
ee1643ce39 | ||
|
|
a82cdcfe48 | ||
|
|
1b439703ff | ||
|
|
4cc5943f90 | ||
|
|
5fad666678 | ||
|
|
e12bf35996 | ||
|
|
d34fccec22 | ||
|
|
429437f1b9 | ||
|
|
c6e7d87960 | ||
|
|
716320f3ca | ||
|
|
1d12b47cb8 | ||
|
|
1bc1ee9e08 | ||
|
|
53f50463bc | ||
|
|
7ab91e660f | ||
|
|
2f0e230522 | ||
|
|
280f674ce9 | ||
|
|
a92c66d512 | ||
|
|
c45eedcb02 | ||
|
|
a9a49345ba | ||
|
|
8d960a2eb9 | ||
|
|
3e623b8959 | ||
|
|
1b1991d53d | ||
|
|
6d0f39d841 | ||
|
|
3087501b6c | ||
|
|
b429319bc0 | ||
|
|
247e855dbf | ||
|
|
1aec645510 | ||
|
|
3ea2038d3d | ||
|
|
942cb5e87e | ||
|
|
37a3a7cdce | ||
|
|
435a27b66a | ||
|
|
b31a7cdcbf | ||
|
|
ac61548e6a | ||
|
|
f5ace0f72a | ||
|
|
e498b73933 | ||
|
|
ff69bdbc6f | ||
|
|
0c1e184cb7 | ||
|
|
e97541dcbc | ||
|
|
7b3eb22865 | ||
|
|
d55f065ce2 | ||
|
|
86af244636 | ||
|
|
2c9e2b2e3c | ||
|
|
33c8bf886e | ||
|
|
ef71a089a6 | ||
|
|
5fc98cce0d | ||
|
|
b9101c3d6a | ||
|
|
6aab0f627c | ||
|
|
6b97673d0a | ||
|
|
5d8c1ce84e | ||
|
|
33c9591a4b | ||
|
|
87e8736823 | ||
|
|
c0da16bfcd | ||
|
|
a4ddc5b3ac | ||
|
|
91e4010039 | ||
|
|
486b6580d8 | ||
|
|
9c4ef27d49 | ||
|
|
33577eaa68 | ||
|
|
d5e19661bd | ||
|
|
799afac05b | ||
|
|
3ba36dc30c | ||
|
|
641024c235 | ||
|
|
d9598db117 | ||
|
|
2e4da07a15 | ||
|
|
40f4411b69 | ||
|
|
c75de0f37c | ||
|
|
74c4c1bf44 | ||
|
|
60a637921c | ||
|
|
22312b3c9c | ||
|
|
2e26e44538 | ||
|
|
24e79ecc68 | ||
|
|
5b532a1812 | ||
|
|
f3867d7f80 | ||
|
|
fb90e47e70 | ||
|
|
68046244dd | ||
|
|
b1507060ad | ||
|
|
ffbd595d88 | ||
|
|
ed5bc1e69c | ||
|
|
9734931f67 | ||
|
|
0048b04540 | ||
|
|
c361932fe2 | ||
|
|
2d8feabe54 | ||
|
|
1b511dd130 | ||
|
|
52024f4d80 | ||
|
|
735fa6287f | ||
|
|
7eb407fe2b | ||
|
|
897d5c58b3 | ||
|
|
dc9086512b | ||
|
|
0029d068c7 | ||
|
|
de388b3dc8 | ||
|
|
fb904d53cd | ||
|
|
600cc02de3 | ||
|
|
946d0cd219 | ||
|
|
4d0b964e36 | ||
|
|
2b12ab4d5a | ||
|
|
8114957e6d | ||
|
|
50edef4ab2 | ||
|
|
e5a991988f | ||
|
|
e85eb6d0f4 | ||
|
|
6949f35f22 | ||
|
|
e0391b93c4 | ||
|
|
4a5e775a2b | ||
|
|
323f019350 | ||
|
|
98053c2d4c | ||
|
|
aab338760c | ||
|
|
ab9a2b1728 | ||
|
|
6a38d3bcf3 | ||
|
|
76f3cbdf4c | ||
|
|
d45d58b6bf | ||
|
|
f32a422330 | ||
|
|
74d4be28dd | ||
|
|
b4a31bd292 | ||
|
|
cc1adf9b38 | ||
|
|
1601b3b6b0 | ||
|
|
61cbdd1a19 | ||
|
|
a3ee6131a3 | ||
|
|
6dfddaa453 | ||
|
|
de696b7092 | ||
|
|
9165233657 | ||
|
|
aa3a417e97 | ||
|
|
996f48fcf0 | ||
|
|
81d83f629f | ||
|
|
5e3b0bf348 | ||
|
|
4a31463299 | ||
|
|
8a5471e175 | ||
|
|
605fd9f8e1 | ||
|
|
2bda43875d | ||
|
|
11edc9e7a7 | ||
|
|
3b9b823511 | ||
|
|
da0ecf59c6 | ||
|
|
e5b1fdf668 | ||
|
|
204fb82975 | ||
|
|
37839e2709 | ||
|
|
dbaedb5995 | ||
|
|
0a832e90bd | ||
|
|
b4e908d04d | ||
|
|
4619d29b78 | ||
|
|
c63b697636 | ||
|
|
06d29d6fda | ||
|
|
c0f7bc4b5e | ||
|
|
7139c9ae59 | ||
|
|
0ae00fc921 | ||
|
|
fe456cb83d | ||
|
|
a8432ed4a4 | ||
|
|
04f910b747 | ||
|
|
1c3de70155 | ||
|
|
b73642f8a8 | ||
|
|
479b497528 | ||
|
|
31b55d3844 | ||
|
|
dbf4e08d09 | ||
|
|
274359e6ee | ||
|
|
8687dcbce1 | ||
|
|
03dfbdb7b1 | ||
|
|
3c8519f245 | ||
|
|
4d2cc3ebdd | ||
|
|
6e2758ae26 | ||
|
|
4637e06ad2 | ||
|
|
764399256c | ||
|
|
f4ca4edc64 | ||
|
|
872a1216a7 | ||
|
|
8c75674591 | ||
|
|
e6244ca204 | ||
|
|
f540362e36 | ||
|
|
2be6699a6a | ||
|
|
09c10492ab | ||
|
|
c8e4b1fc84 | ||
|
|
0de7cece5b | ||
|
|
a3413a6749 | ||
|
|
b104ab9491 | ||
|
|
269c5dce60 | ||
|
|
a39c81c63f | ||
|
|
d699247269 | ||
|
|
7caafb4014 | ||
|
|
f1546abf09 | ||
|
|
3083562f6f | ||
|
|
da2ee70462 | ||
|
|
7e9dda3c5e | ||
|
|
0b96f88875 | ||
|
|
f13ffe2098 | ||
|
|
bca5d26583 | ||
|
|
660bc757f1 | ||
|
|
ca927fe587 | ||
|
|
9df8966f4a | ||
|
|
3429f41489 | ||
|
|
0c7c4924ee | ||
|
|
8f40d6617e | ||
|
|
af9e85bda1 | ||
|
|
717f45d117 | ||
|
|
35c53865fb | ||
|
|
a1d1d6d3d4 | ||
|
|
d17f812827 | ||
|
|
3916758529 | ||
|
|
2396181bc5 | ||
|
|
6e8640bf1b | ||
|
|
c2c7c7bd9a | ||
|
|
071a1c4adb | ||
|
|
d5b2dda2e8 | ||
|
|
2ac281eb3e | ||
|
|
5e81543448 | ||
|
|
b32f925468 | ||
|
|
fdeb6bcae0 | ||
|
|
76232cd9e7 | ||
|
|
4da9b5e491 | ||
|
|
c4504a9221 | ||
|
|
65de8359e7 | ||
|
|
f6fab74436 | ||
|
|
350ba264e8 | ||
|
|
29e24818a1 | ||
|
|
71cd6f7b90 | ||
|
|
84ba253791 | ||
|
|
fce158b8ad | ||
|
|
da13ba6c67 | ||
|
|
7618133298 | ||
|
|
0d1698f81d | ||
|
|
362d642c87 | ||
|
|
e4c96d5be5 | ||
|
|
f488701adc | ||
|
|
8ff2bf51c5 | ||
|
|
a2490a55a9 | ||
|
|
20189f5191 | ||
|
|
06b796c6bd | ||
|
|
ad4edf6c68 | ||
|
|
4100f20a69 | ||
|
|
bedf946fb2 | ||
|
|
b9e67157c6 | ||
|
|
b30b2a183b | ||
|
|
9ab3bcdde3 | ||
|
|
5df3bbe188 | ||
|
|
8cf12416c0 | ||
|
|
b7c2c83c88 | ||
|
|
3b6da93331 | ||
|
|
b4642d3fd4 | ||
|
|
88a2b0b911 | ||
|
|
954e127f1d | ||
|
|
7654add5e5 | ||
|
|
85a37ea53f | ||
|
|
b337acebcc | ||
|
|
fb9ca54c95 | ||
|
|
1a15d41523 | ||
|
|
e378cc5791 | ||
|
|
748c189c79 | ||
|
|
b89be6c4b9 | ||
|
|
df207807b6 | ||
|
|
1f2b40cff1 | ||
|
|
734400fd37 | ||
|
|
f19979d928 | ||
|
|
19be7a53da | ||
|
|
e56af34fb0 | ||
|
|
7737aa20e8 | ||
|
|
ead046201c | ||
|
|
0aa7c3f659 | ||
|
|
4aa7222022 | ||
|
|
86e3c78776 | ||
|
|
40076287ea | ||
|
|
ca81db8edf | ||
|
|
ae68a80e98 | ||
|
|
beb7c58375 | ||
|
|
e080b9d565 | ||
|
|
ca2db37039 | ||
|
|
194825f78e | ||
|
|
55bd765ea0 | ||
|
|
b03d61e2cf | ||
|
|
6fc0e5167b | ||
|
|
0065be011f | ||
|
|
3f7cbce58c | ||
|
|
246b62e322 | ||
|
|
7c2fdd1ee9 | ||
|
|
f77aa2623c | ||
|
|
20847a3ff5 | ||
|
|
eb6d42acf9 | ||
|
|
094d676a8b | ||
|
|
71306ceb1d | ||
|
|
8bbfc7fc22 | ||
|
|
19baba12b1 | ||
|
|
15b8819136 | ||
|
|
3fae8ade05 | ||
|
|
f9bbf31d65 | ||
|
|
df1da3dda9 | ||
|
|
c83f2a4abd | ||
|
|
ad53833040 | ||
|
|
bc8c85668a | ||
|
|
d12a3dde45 | ||
|
|
301c878c0f | ||
|
|
bd55bfa071 | ||
|
|
6d2f09b579 | ||
|
|
4bfea7f54d | ||
|
|
55906486d8 | ||
|
|
d5478e6e08 | ||
|
|
d88d85c172 | ||
|
|
59c3c536c7 | ||
|
|
a007458cb8 | ||
|
|
d051912f21 | ||
|
|
a547158a50 | ||
|
|
95f2351aa0 | ||
|
|
698aaffb0b | ||
|
|
73eccecbf8 | ||
|
|
ae4a261463 | ||
|
|
c9f0d0cec2 | ||
|
|
4fa1e45d45 | ||
|
|
1b3d252bfe | ||
|
|
a9ba4a9fcd | ||
|
|
7f49619875 | ||
|
|
696660639a | ||
|
|
da4323062d | ||
|
|
a901e171b2 | ||
|
|
6e41d532fe | ||
|
|
4fc78ffb58 | ||
|
|
8137f41fc3 | ||
|
|
2e9471797d | ||
|
|
344248cea0 | ||
|
|
2789e3dba5 | ||
|
|
cca759a41e | ||
|
|
4f7b3d8882 | ||
|
|
2b330b78b7 | ||
|
|
d47ca1912b | ||
|
|
3fd2108b10 | ||
|
|
96e2a407f4 | ||
|
|
cdf18c96f4 | ||
|
|
53acaa05b8 | ||
|
|
fb85679068 | ||
|
|
9558e14479 | ||
|
|
4af0af93bf | ||
|
|
df4bc950fe | ||
|
|
250394f72b | ||
|
|
ca83fd6dc1 | ||
|
|
d5e9e7cd2b | ||
|
|
9a96f621ef | ||
|
|
5d7ce096c6 | ||
|
|
c9f8109c06 | ||
|
|
a20b4f2864 | ||
|
|
44a19d2a0a | ||
|
|
02f3beb8db | ||
|
|
3269cc3d90 | ||
|
|
fb70a1f4ab | ||
|
|
df0aa483ce | ||
|
|
c83f12a55c | ||
|
|
9704f59566 | ||
|
|
2923893d34 | ||
|
|
890dab0742 | ||
|
|
607e26b041 | ||
|
|
ea75290f65 | ||
|
|
a176054118 | ||
|
|
9a697dc5f5 | ||
|
|
cfdb852843 | ||
|
|
2e67a91982 | ||
|
|
074ca9330d | ||
|
|
f0d7cdcb20 | ||
|
|
40d961e059 | ||
|
|
e5de759236 | ||
|
|
e26a75c59d | ||
|
|
8701145b40 | ||
|
|
a2558886c8 | ||
|
|
f818ee86ae | ||
|
|
ad0dbdaa9c | ||
|
|
a9f14b294f | ||
|
|
a435ae98f9 | ||
|
|
481b261458 | ||
|
|
48df52d743 | ||
|
|
0af0d3b171 | ||
|
|
8287cf35e7 | ||
|
|
fab7924cc2 | ||
|
|
0ab739e8b1 | ||
|
|
2dcd4d171b | ||
|
|
e7f4d18c3d | ||
|
|
1611362c22 | ||
|
|
2327698160 | ||
|
|
71c1f00ec2 | ||
|
|
6574a126ef | ||
|
|
1e68086355 | ||
|
|
326cc8fd67 | ||
|
|
4afcb421bd | ||
|
|
8d21917035 | ||
|
|
4ca7f8834c | ||
|
|
b43299c8da | ||
|
|
b763809f5e | ||
|
|
2cb97f7475 | ||
|
|
6283df7491 | ||
|
|
acc4490370 | ||
|
|
f85c1a995a | ||
|
|
809e5fda8a | ||
|
|
dce245da5a | ||
|
|
d261c4cd27 | ||
|
|
c33299d542 | ||
|
|
ebdf8a5f3c | ||
|
|
c8852d183f | ||
|
|
9f161b20ef | ||
|
|
40f9d64973 | ||
|
|
4a2e68a0fd | ||
|
|
bcd90d3401 | ||
|
|
114af7d33f | ||
|
|
7b83d2de49 | ||
|
|
850de5913d | ||
|
|
bb9ee46f40 | ||
|
|
e94fc1305b | ||
|
|
3e4e8feb29 | ||
|
|
fedf347b1a | ||
|
|
285277a50b | ||
|
|
323c96f42f | ||
|
|
7dee344ea9 | ||
|
|
65bce588e4 | ||
|
|
233ff1b744 | ||
|
|
0837e39787 | ||
|
|
86db565a21 | ||
|
|
d6ac5e5001 | ||
|
|
e6443f1981 | ||
|
|
d13e6c73db | ||
|
|
79ca7f3cb5 | ||
|
|
cfd07ccd34 | ||
|
|
48047d523a | ||
|
|
eeb8fc2626 | ||
|
|
3d1baf3f2f | ||
|
|
4e382d6765 | ||
|
|
582963375d | ||
|
|
56c7c1bcc8 | ||
|
|
f88e57ddb8 | ||
|
|
9d98e012e4 | ||
|
|
d305a774f0 | ||
|
|
16b0c8d353 | ||
|
|
55da4fdbf6 | ||
|
|
ed2fbd8f25 | ||
|
|
42199bc8e5 | ||
|
|
7c5318768c | ||
|
|
aba25aab19 | ||
|
|
f99bd33f91 | ||
|
|
a6a6ce83f0 | ||
|
|
f4908a9758 | ||
|
|
5e4ca4b76a | ||
|
|
1e938d0e90 | ||
|
|
f3704f4c05 | ||
|
|
8800efe953 | ||
|
|
a320c4584e | ||
|
|
3841850168 | ||
|
|
beb3885840 | ||
|
|
06967c0c46 | ||
|
|
9a382c572c | ||
|
|
44b6c371db | ||
|
|
00970be996 | ||
|
|
aca4ab015f | ||
|
|
68b63d5783 | ||
|
|
4b499f2bb1 | ||
|
|
ed17581f92 | ||
|
|
a46c4ec912 | ||
|
|
930cbeec17 | ||
|
|
10689ffaba | ||
|
|
29b0ea0af9 | ||
|
|
57d00946be | ||
|
|
ef51de72c9 | ||
|
|
c807bf1e0e | ||
|
|
2525b3fb05 | ||
|
|
9163ce0f6e | ||
|
|
d776638f53 | ||
|
|
83fff41312 | ||
|
|
dd7d9bc95b | ||
|
|
f8eabbc100 | ||
|
|
7ed18ac62d | ||
|
|
3ac707c645 | ||
|
|
8e9a1e0bf3 | ||
|
|
bc31b5d27a | ||
|
|
936738b750 | ||
|
|
7c3048ab9c | ||
|
|
64719f3ace | ||
|
|
a11a5f04d5 | ||
|
|
eb5c035dde | ||
|
|
c3887efbf3 | ||
|
|
495585830d | ||
|
|
6715cb9880 | ||
|
|
41b167d23c | ||
|
|
7ea8b54210 | ||
|
|
bcea39a858 | ||
|
|
fb560abac4 | ||
|
|
ba93a08b40 | ||
|
|
2be6b3481c | ||
|
|
6ef44a6fbb | ||
|
|
2afe40a0b5 | ||
|
|
e57d004718 | ||
|
|
d780d0aabb | ||
|
|
0f9e3f0767 | ||
|
|
381972c923 | ||
|
|
845d7ad718 | ||
|
|
f1b6c0c559 | ||
|
|
e39eddf3fe | ||
|
|
72218fb475 | ||
|
|
9a3e497c22 | ||
|
|
85d510cd48 | ||
|
|
786c65ea5f | ||
|
|
10e6f61125 | ||
|
|
cdd06e7236 | ||
|
|
48603c0ee2 | ||
|
|
63f30492be | ||
|
|
0e8772290d | ||
|
|
6cfc5798b0 | ||
|
|
6be275f5d4 | ||
|
|
716f237c4c | ||
|
|
2a192be4f5 | ||
|
|
2679185a09 | ||
|
|
b85e7ab0b1 | ||
|
|
29c9804843 | ||
|
|
56d8ddbaaf | ||
|
|
8b324249b1 | ||
|
|
59cc61529b | ||
|
|
3912e5ef0b | ||
|
|
e40fbf1470 | ||
|
|
56a03e1a10 | ||
|
|
5d5952d354 | ||
|
|
53fda88d4c | ||
|
|
c4f306c145 | ||
|
|
e01d7fcefc | ||
|
|
aec04b07e0 | ||
|
|
b1872a8e21 | ||
|
|
634816d378 | ||
|
|
2fd5a6d47f | ||
|
|
8dca56521b | ||
|
|
a41aefe77d | ||
|
|
46dbc7157d | ||
|
|
59261113d8 | ||
|
|
fc2834cf04 | ||
|
|
a15633053b | ||
|
|
60a06eef19 | ||
|
|
7fd6ddc25b | ||
|
|
c49e0ac5c8 | ||
|
|
a51e95d052 | ||
|
|
4df9d70e4a | ||
|
|
78d490d5e4 | ||
|
|
2f6002b197 | ||
|
|
abcb95b8a1 | ||
|
|
bf435cae7c | ||
|
|
4b38acd540 | ||
|
|
f71749c3c4 | ||
|
|
cbc90e7ffb | ||
|
|
62866dc8be | ||
|
|
11e702c430 | ||
|
|
3e6e6ec0a5 | ||
|
|
898c08c8e0 | ||
|
|
88fba101a3 | ||
|
|
b0f431e1a2 | ||
|
|
42a7aca504 | ||
|
|
c017f2e7c4 | ||
|
|
d17bcd8afe | ||
|
|
874673f64f | ||
|
|
e052d73321 | ||
|
|
58efab5cdf | ||
|
|
4360fe492e | ||
|
|
295faf726b | ||
|
|
2da9d46ca6 | ||
|
|
e4f1e5f4c3 | ||
|
|
c695af31b8 | ||
|
|
24753c8c6a | ||
|
|
6196cf09ff | ||
|
|
28eb5b9bc4 | ||
|
|
bb20331f9e | ||
|
|
d2bce042a5 | ||
|
|
5d57263a15 | ||
|
|
bded8755a1 | ||
|
|
2e9ade61b2 | ||
|
|
89e03a86b7 | ||
|
|
48e88e4e74 | ||
|
|
d182ecb2d3 | ||
|
|
27e4503dc6 | ||
|
|
72b596efb3 | ||
|
|
0d1de96dbc | ||
|
|
788f69a8c9 | ||
|
|
08b63b4f01 | ||
|
|
ba07dc1804 | ||
|
|
d46074e0ad | ||
|
|
d651063749 | ||
|
|
f60f8396bb | ||
|
|
919fdd70b8 | ||
|
|
ab2702070b | ||
|
|
057e1a1aff | ||
|
|
a2af4e1284 | ||
|
|
97adede70b | ||
|
|
b6447a9032 | ||
|
|
e40b5819bd | ||
|
|
16926edf18 | ||
|
|
8203c79f76 | ||
|
|
43e1b27d16 | ||
|
|
d1cb3b0d15 | ||
|
|
266b3b8678 | ||
|
|
a2629c4929 | ||
|
|
c1fc629c54 | ||
|
|
0d12fe43a0 | ||
|
|
6aec0ce702 | ||
|
|
32c30c34e9 | ||
|
|
6b7b2612a9 | ||
|
|
0b9c6ed178 | ||
|
|
d903855aa3 | ||
|
|
89234bcd42 | ||
|
|
85ba590fa9 | ||
|
|
2950f77dbc | ||
|
|
a94f5ba200 | ||
|
|
0c4e40102f | ||
|
|
27e8126b18 | ||
|
|
bf860b21d7 | ||
|
|
a03a540156 | ||
|
|
eb63c8dcb8 | ||
|
|
cdcb94751e | ||
|
|
cd5d8cceb8 | ||
|
|
8fbc87be46 | ||
|
|
06fba42858 | ||
|
|
0f8a1e3901 | ||
|
|
729dfdfed7 | ||
|
|
1b8051dfe5 | ||
|
|
be6454193b | ||
|
|
f3347be629 | ||
|
|
dbce06500d | ||
|
|
7a81dd3378 | ||
|
|
57dd9c9e01 | ||
|
|
ef4e52a60e | ||
|
|
e7cbefa316 | ||
|
|
b4f805b4e9 | ||
|
|
9b0d26aedd | ||
|
|
f6758c397d | ||
|
|
ef3ed6e338 | ||
|
|
45aa8742d8 | ||
|
|
ebe8f554c6 | ||
|
|
45b0e63be2 | ||
|
|
934dc842e0 | ||
|
|
deda877355 | ||
|
|
2dba8404eb | ||
|
|
f581b4e92c | ||
|
|
02c74b5bee | ||
|
|
df69439b9c | ||
|
|
eb4a686b14 | ||
|
|
3386466e7a | ||
|
|
6a2aa7e4f0 | ||
|
|
735871d501 | ||
|
|
097f3590ae | ||
|
|
17bf13fcb6 | ||
|
|
2dc7b7ad78 | ||
|
|
a3c1724d17 | ||
|
|
5a9309de78 | ||
|
|
a40fae04ce | ||
|
|
f8cb6979d7 | ||
|
|
fc70ae180e | ||
|
|
66b5fa821c | ||
|
|
2f2f416bea | ||
|
|
1da07a3b86 | ||
|
|
ad0fcb745e | ||
|
|
5a502d451d | ||
|
|
955824e634 | ||
|
|
3b62f3c9c0 | ||
|
|
d2a27a84cf | ||
|
|
c7d8eb126f | ||
|
|
d608fd77b9 | ||
|
|
af5aa38bc3 | ||
|
|
2f2f367c0b | ||
|
|
d7a2362a76 | ||
|
|
e479c8a553 | ||
|
|
62f707f501 | ||
|
|
19d62b7a68 | ||
|
|
103bda04d9 | ||
|
|
8e6846d9da | ||
|
|
fd38216eda | ||
|
|
ae27b8944e | ||
|
|
bb6b825836 | ||
|
|
3fc55bba8e | ||
|
|
92819f5082 | ||
|
|
736b9074c8 | ||
|
|
376147911f | ||
|
|
4281690021 | ||
|
|
65714165f9 | ||
|
|
82d917c2c5 | ||
|
|
8487d67f00 | ||
|
|
67d1dad77c | ||
|
|
3b39c3391d | ||
|
|
8a55c6fd9f | ||
|
|
68567e763c | ||
|
|
bc2d3a13f4 | ||
|
|
e0bca07e06 | ||
|
|
377f194837 | ||
|
|
de9989d5a2 | ||
|
|
50db34457c | ||
|
|
b1ce6bd5cc | ||
|
|
81915540de | ||
|
|
0d65f08b1d | ||
|
|
ffbd1fd474 | ||
|
|
700c1f836d | ||
|
|
db2c6820ee | ||
|
|
3236607be4 | ||
|
|
3edbeb8902 | ||
|
|
f59467b897 | ||
|
|
6bc81d3d26 | ||
|
|
4c26792c9b | ||
|
|
9a133ced2d | ||
|
|
18bebaf5c3 | ||
|
|
f7efae93d5 | ||
|
|
7b4d2118ea | ||
|
|
26eb7c9375 | ||
|
|
e4d5367ead | ||
|
|
47b5157f01 | ||
|
|
39444d83c5 | ||
|
|
350028553b | ||
|
|
7392add8e0 | ||
|
|
e14695c96e | ||
|
|
b4d3806f10 | ||
|
|
996afe7d95 | ||
|
|
905cadc00e | ||
|
|
6634751303 | ||
|
|
64b57fa907 | ||
|
|
dd4059beb8 | ||
|
|
fe3b54bc2e | ||
|
|
1b5e1943f5 | ||
|
|
b1e6fe7139 | ||
|
|
92718a819c | ||
|
|
ceb2f6894f | ||
|
|
c42612abac | ||
|
|
7069d7d802 | ||
|
|
9aaa6d5df1 | ||
|
|
3eb155cf2a | ||
|
|
7c8d914711 | ||
|
|
4d1f8bd057 | ||
|
|
b883ce95b2 | ||
|
|
546e7c0c1f | ||
|
|
4f2dc0ecff | ||
|
|
03c5d06107 | ||
|
|
9499047f8e | ||
|
|
db5674cb08 | ||
|
|
66d000f4ba | ||
|
|
2c3c990019 | ||
|
|
807aecdb11 | ||
|
|
ea1b705c1c | ||
|
|
cb8b0d3597 | ||
|
|
7a86514505 |
+12
-2
@@ -1,3 +1,5 @@
|
||||
\#*
|
||||
.#*
|
||||
*~
|
||||
*.old
|
||||
*.gz
|
||||
@@ -6,16 +8,24 @@
|
||||
*.info
|
||||
*.log
|
||||
*.1
|
||||
.*.swp
|
||||
*.tmp
|
||||
*.tex
|
||||
*.pdf
|
||||
/Makefile
|
||||
README
|
||||
TAGS
|
||||
autom4te.cache
|
||||
config.cache
|
||||
config.status
|
||||
configure
|
||||
dddrun*
|
||||
doxygen-doc
|
||||
gdbrun*
|
||||
gmon.out
|
||||
internals.txt
|
||||
verilator.txt
|
||||
verilator.pdf
|
||||
verilator_bin*
|
||||
autom4te.cache
|
||||
verilator_coverage_bin*
|
||||
verilator.pc
|
||||
**/obj_dir/*
|
||||
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
+21
-6
@@ -4,25 +4,40 @@
|
||||
\.svn/
|
||||
\.(bak|old)/
|
||||
\.(bak|old)$
|
||||
\bMakefile$
|
||||
\.tar\.
|
||||
.*\.tgz
|
||||
.*\.log
|
||||
\..*\.swp
|
||||
.*\.tmp
|
||||
.*\.tex
|
||||
.*\.key
|
||||
.*\.vcd
|
||||
.*\.1
|
||||
/obj_dir/
|
||||
/obj_dbg/
|
||||
/obj_opt/
|
||||
/INCA_libs/
|
||||
/cov_work/
|
||||
/logs/
|
||||
Makefile
|
||||
src/Makefile_obj
|
||||
include/verilated.mk
|
||||
config.cache
|
||||
config.status
|
||||
^Makefile$
|
||||
src/Makefile$
|
||||
src/Makefile_obj$
|
||||
include/verilated.mk$
|
||||
test_regress/.gdbinit$
|
||||
config.cache$
|
||||
config.status$
|
||||
verilator.log
|
||||
verilator.tex
|
||||
verilator.pc$
|
||||
verilator_bin.*
|
||||
verilator_coverage_bin.*
|
||||
.vcsmx_rebuild$
|
||||
autom4te\.cache/
|
||||
nodist/
|
||||
/simv$
|
||||
/simv.daidir/
|
||||
/vc_hdrs.h$
|
||||
/csrc/
|
||||
doxygen-doc/.*
|
||||
TAGS
|
||||
.*~
|
||||
|
||||
+239
-107
@@ -3,13 +3,11 @@
|
||||
#
|
||||
# This file is part of Verilator.
|
||||
#
|
||||
# Author: Wilson Snyder <[email protected]>
|
||||
#
|
||||
# Code available from: http://www.veripool.org/verilator
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2017 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.
|
||||
@@ -44,9 +42,6 @@
|
||||
# reconstructed with this Makefile. This typically includes
|
||||
# everything deleted by distclean, plus more: C source files
|
||||
# produced by Bison, tags tables, info files, and so on.
|
||||
#
|
||||
# make extraclean
|
||||
# Still more severe - delete backup and autosave files, too.
|
||||
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
@@ -54,11 +49,13 @@ srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
HOST = @HOST@
|
||||
|
||||
DOXYGEN = doxygen
|
||||
INSTALL = @INSTALL@
|
||||
INSTALL_PROGRAM = @INSTALL_PROGRAM@
|
||||
INSTALL_DATA = @INSTALL_DATA@
|
||||
MAKEINFO = makeinfo
|
||||
TEXI2DVI = texi2dvi
|
||||
POD2TEXT = pod2text
|
||||
POD2LATEXFIX = $(srcdir)/src/pod2latexfix
|
||||
PERL = @PERL@
|
||||
|
||||
# Destination prefix for RPMs
|
||||
@@ -71,7 +68,7 @@ exec_prefix = @exec_prefix@
|
||||
# Directory in which to install scripts.
|
||||
bindir = @bindir@
|
||||
|
||||
# Directory in which to install scripts.
|
||||
# Directory in which to install manpages.
|
||||
mandir = @mandir@
|
||||
|
||||
# Directory in which to install library files.
|
||||
@@ -84,94 +81,121 @@ infodir = @infodir@
|
||||
# Generally ${prefix}/share/verilator
|
||||
pkgdatadir = @pkgdatadir@
|
||||
|
||||
# Directory in which to install pkgconfig file
|
||||
# Generall ${prefix}/share/pkgconfig
|
||||
pkgconfigdir = @pkgconfigdir@
|
||||
|
||||
# Directory in which to install data across multiple architectures
|
||||
datarootdir = @datarootdir@
|
||||
|
||||
# Compile options
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
PACKAGE_VERSION = @PACKAGE_VERSION@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
######################################################################
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
SUBDIRS = src test_verilated test_c test_sc test_sp test_regress test_vcs
|
||||
SUBDIRS = src test_verilated test_c test_sc test_regress
|
||||
|
||||
INFOS = README verilator.txt verilator.html verilator.1 verilator.pdf
|
||||
INFOS = README README.html README.pdf internals.txt internals.html \
|
||||
internals.pdf verilator.txt verilator.html verilator.pdf \
|
||||
$(VL_INST_MAN_FILES)
|
||||
|
||||
# Files that can be generated, but should be up to date for a distribution.
|
||||
DISTDEP = info Makefile
|
||||
# Files to distribute.
|
||||
DISTBIN = $(wildcard bin/verilator-*)
|
||||
|
||||
DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING *.in *.ac \
|
||||
Changes README TODO \
|
||||
DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
|
||||
*.in *.ac \
|
||||
Changes TODO \
|
||||
MANIFEST.SKIP \
|
||||
bin/* \
|
||||
install-sh configure mkinstalldirs *.texi \
|
||||
include/verilated*.[chv]* \
|
||||
doxygen-mainpage doxygen.config veripool-logo.png \
|
||||
install-sh configure mkinstalldirs *.pod \
|
||||
include/*.[chv]* \
|
||||
include/*.in \
|
||||
include/.*ignore \
|
||||
include/vltstd/*.[chv]* \
|
||||
.*attributes */.*attributes */*/.*attributes \
|
||||
src/.*ignore src/*.in src/*.cpp src/*.[chly] src/astgen src/bisonpre src/*fix \
|
||||
src/.*ignore src/*.in src/*.cpp src/*.[chly] \
|
||||
src/astgen src/bisonpre src/*fix src/cppcheck_filtered \
|
||||
src/vlcovgen \
|
||||
src/.gdbinit \
|
||||
src/*.pl src/*.pod \
|
||||
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
|
||||
test_*/*.pl test_*/*.v test_*/*.vc test_*/vlint \
|
||||
test_*/*.pl test_*/*.v test_*/*.vc test_*/*.vh \
|
||||
test_verilated/vgen*.pl \
|
||||
test_regress/t/t*/*.sv* \
|
||||
test_regress/t/t*/*.v* \
|
||||
test_regress/t/t*/*/*.sv* \
|
||||
test_regress/t/t*/*/*.v* \
|
||||
test_regress/t/*.cpp \
|
||||
test_regress/t/*.h \
|
||||
test_regress/t/*.dat \
|
||||
test_regress/t/*.mem \
|
||||
test_regress/t/*.out \
|
||||
test_regress/t/*.pl \
|
||||
test_regress/t/*.pf \
|
||||
test_regress/t/*.v* \
|
||||
verilator.* \
|
||||
|
||||
INST_PROJ_FILES = \
|
||||
bin/verilator \
|
||||
bin/verilator_coverage \
|
||||
bin/verilator_includer \
|
||||
bin/verilator_profcfunc \
|
||||
include/verilated.[chv]* \
|
||||
include/verilated.mk \
|
||||
include/verilatedos.[chv]* \
|
||||
include/*.[chv]* \
|
||||
include/vltstd/*.[chv]* \
|
||||
|
||||
INST_PROJ_BIN_FILES = \
|
||||
verilator_bin \
|
||||
verilator_bin_dbg \
|
||||
verilator_coverage_bin_dbg \
|
||||
|
||||
DISTFILES := $(DISTFILES_INC)
|
||||
|
||||
VL_INST_MAN_FILES = verilator.1
|
||||
ifeq ($(OBJCACHE_JOBS),)
|
||||
ifneq ($(OBJCACHE_HOSTS),)
|
||||
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
||||
endif
|
||||
endif
|
||||
|
||||
default: all
|
||||
all: all_nomsg msg_test
|
||||
all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
|
||||
|
||||
.PHONY:verilator_exe
|
||||
verilator_exe verilator_bin verilator_bin_dbg:
|
||||
.PHONY:verilator_bin
|
||||
.PHONY:verilator_bin_dbg
|
||||
.PHONY:verilator_coverage_bin_dbg
|
||||
verilator_exe verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg:
|
||||
@echo ------------------------------------------------------------
|
||||
@echo "making verilator in src" ; \
|
||||
(cd src && $(MAKE) )
|
||||
(cd src && $(MAKE) $(OBJCACHE_JOBS) )
|
||||
|
||||
.PHONY:msg_test
|
||||
msg_test:
|
||||
msg_test: all_nomsg
|
||||
@echo "Build complete!"
|
||||
@echo
|
||||
@echo "Type 'make test' to test."
|
||||
@echo
|
||||
|
||||
.PHONY:test
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
test: test_vcs test_c test_sc test_sp test_verilated test_regress
|
||||
ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users
|
||||
test: test_c test_sc test_verilated test_regress
|
||||
else
|
||||
test: test_c test_sc test_sp
|
||||
test: test_c test_sc
|
||||
endif
|
||||
@echo "Tests passed!"
|
||||
@echo
|
||||
@echo "Type 'make install' to install documentation."
|
||||
@echo
|
||||
|
||||
test_vcs: all_nomsg
|
||||
@(cd test_vcs && $(MAKE))
|
||||
test_c: all_nomsg
|
||||
@(cd test_c && $(MAKE))
|
||||
test_c_debug: all_nomsg
|
||||
@@ -180,10 +204,6 @@ test_sc: all_nomsg
|
||||
@(cd test_sc && $(MAKE))
|
||||
test_sc_debug: all_nomsg
|
||||
@(cd test_sc && $(MAKE) test_debug)
|
||||
test_sp: all_nomsg
|
||||
@(cd test_sp && $(MAKE))
|
||||
test_sp_debug: all_nomsg
|
||||
@(cd test_sp && $(MAKE) test_debug)
|
||||
test_verilated: all_nomsg
|
||||
@(cd test_verilated && $(MAKE))
|
||||
test_regress: all_nomsg
|
||||
@@ -192,82 +212,157 @@ test_regress: all_nomsg
|
||||
info: $(INFOS)
|
||||
|
||||
# Use --no-split to avoid creating filenames > 14 chars.
|
||||
verilator.1: bin/verilator
|
||||
%.1: ${srcdir}/bin/%
|
||||
pod2man $< $@
|
||||
|
||||
verilator.txt: bin/verilator
|
||||
pod2text $< $@
|
||||
verilator.txt: ${srcdir}/bin/verilator
|
||||
$(POD2TEXT) $< $@
|
||||
|
||||
verilator.html: bin/verilator
|
||||
verilator.html: ${srcdir}/bin/verilator
|
||||
pod2html $< >$@
|
||||
|
||||
verilator.pdf: bin/verilator $(DISTCONFIG)
|
||||
pod2latex --full --out verilator.tex bin/verilator
|
||||
cat < verilator.tex \
|
||||
| sed 's/\\begin{document}/\\usepackage[left=1.7in,right=1.7in,top=1.3in,bottom=1.3in]{geometry}\n\\begin{document}/' \
|
||||
| sed 's/\\begin{document}/\\usepackage[pdftex,bookmarks=true,bookmarksnumbered=true,hypertexnames=false,breaklinks=true,linkbordercolor={0 0 1}]{hyperref}\n\\begin{document}/' \
|
||||
| sed 's/\\begin{document}/\\usepackage{fancyhdr} \\pagestyle{fancy}\n\\begin{document}/' \
|
||||
| sed 's/\\begin{document}/\\setlength{\\parindent}{0pt} \\setlength{\\parskip}{\\baselineskip}\n\\begin{document}/' \
|
||||
| sed 's/\\begin{document}/\\title{$(DISTTITLE)} \\date{${DISTDATE}} \\author{Wilson Snyder\\\\ http:\/\/www.veripool.org}\n\\begin{document}/' \
|
||||
| sed 's/\\begin{document}/\\lhead[$(DISTTITLE)]{$(DISTTITLE)}\n\\begin{document}/' \
|
||||
| sed 's/\\tableofcontents/\\begin{titlepage} \\maketitle \\end{titlepage}\n\\tableofcontents/' \
|
||||
> verilator2.tex
|
||||
# PDF needs DIST variables; but having configure.ac as dependency isn't detected
|
||||
verilator.pdf: ${srcdir}/bin/verilator Makefile
|
||||
pod2latex --full --out verilator.tex ${srcdir}/bin/verilator
|
||||
$(PERL) $(POD2LATEXFIX) "$(DISTTITLE)" "${DISTDATE}" < verilator.tex > verilator2.tex
|
||||
mv verilator2.tex verilator.tex
|
||||
pdflatex verilator.tex
|
||||
pdflatex verilator.tex
|
||||
-rm -f verilator.toc verilator.aux verilator.idx verilator.out
|
||||
|
||||
INSTALL: install.texi
|
||||
$(MAKEINFO) -I$(srcdir) $(srcdir)/install.texi --output=$@ \
|
||||
--no-headers --no-validate
|
||||
README: README.pod
|
||||
-rm -f $@
|
||||
$(POD2TEXT) --loose $< > $@
|
||||
|
||||
README: readme.texi
|
||||
$(MAKEINFO) -I$(srcdir) $(srcdir)/readme.texi --output=$@ \
|
||||
--no-headers --no-validate
|
||||
README.html: README.pod
|
||||
pod2html $< >$@
|
||||
|
||||
# See uninstall also
|
||||
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
|
||||
verilator_includer verilator_profcfunc
|
||||
# PDF needs DIST variables; but having configure.ac as dependency isn't detected
|
||||
README.pdf: README.pod Makefile
|
||||
pod2latex --full --out README.tex README.pod
|
||||
$(PERL) $(POD2LATEXFIX) "$(DISTTITLE) README File" "${DISTDATE}" < README.tex > README2.tex
|
||||
mv README2.tex README.tex
|
||||
pdflatex README.tex
|
||||
pdflatex README.tex
|
||||
-rm -f README.toc README.aux README.idx README.out
|
||||
|
||||
internals.txt: internals.pod
|
||||
-rm -f $@
|
||||
$(POD2TEXT) --loose $< > $@
|
||||
|
||||
internals.html: internals.pod
|
||||
pod2html $< >$@
|
||||
|
||||
# PDF needs DIST variables; but having configure.ac as dependency isn't detected
|
||||
internals.pdf: internals.pod Makefile
|
||||
pod2latex --full --out internals.tex internals.pod
|
||||
$(PERL) $(POD2LATEXFIX) "$(DISTTITLE) Internals Manual" "${DISTDATE}" < internals.tex > internals2.tex
|
||||
mv internals2.tex internals.tex
|
||||
pdflatex internals.tex
|
||||
pdflatex internals.tex
|
||||
-rm -f internals.toc internals.aux internals.idx internals.out
|
||||
|
||||
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||
VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg \
|
||||
verilator_coverage verilator_includer verilator_profcfunc
|
||||
# Some scripts go into both the search path and pkgdatadir,
|
||||
# so they can be found by the user, and under $VERILATOR_ROOT.
|
||||
|
||||
# See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
|
||||
VL_INST_MAN_FILES = verilator.1 verilator_coverage.1 verilator_profcfunc.1
|
||||
|
||||
VL_INST_INC_BLDDIR_FILES = \
|
||||
include/verilated_config.h \
|
||||
include/verilated.mk \
|
||||
|
||||
# Files under srcdir, instead of build time
|
||||
VL_INST_INC_SRCDIR_FILES = \
|
||||
include/*.[chv]* \
|
||||
include/vltstd/*.[chv]* \
|
||||
|
||||
VL_INST_DATA_SRCDIR_FILES = \
|
||||
test_v/*.[chv]* \
|
||||
test_c/*.[chv]* test_c/Makefile test_c/Makefile_obj \
|
||||
test_sc/*.[chv]* test_sc/Makefile test_sc/Makefile_obj \
|
||||
|
||||
installbin:
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
|
||||
( cd bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
||||
( cd bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_coverage $(DESTDIR)$(bindir)/verilator_coverage )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc )
|
||||
( $(INSTALL_PROGRAM) verilator_bin $(DESTDIR)$(bindir)/verilator_bin )
|
||||
( $(INSTALL_PROGRAM) verilator_bin_dbg $(DESTDIR)$(bindir)/verilator_bin_dbg )
|
||||
( $(INSTALL_PROGRAM) verilator_coverage_bin_dbg $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg )
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/bin
|
||||
( cd bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
|
||||
( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
|
||||
|
||||
installman:
|
||||
# Man files can either be part of the original kit, or built in current directory
|
||||
# So important we use $< so VPATH is searched
|
||||
installman: $(VL_INST_MAN_FILES)
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(mandir)/man1
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
$(INSTALL_PROGRAM) $$p $(DESTDIR)$(mandir)/man1/$$p; \
|
||||
cd $(srcdir) \
|
||||
; for p in $(VL_INST_MAN_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(mandir)/man1/$$p; \
|
||||
done
|
||||
|
||||
installdata:
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples
|
||||
cp -r include $(DESTDIR)$(pkgdatadir)
|
||||
cp -r test_c $(DESTDIR)$(pkgdatadir)/examples
|
||||
cp -r test_sc $(DESTDIR)$(pkgdatadir)/examples
|
||||
cp -r test_sp $(DESTDIR)$(pkgdatadir)/examples
|
||||
cp -r test_v $(DESTDIR)$(pkgdatadir)/examples
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||
for p in $(VL_INST_INC_BLDDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
done
|
||||
cd $(srcdir) \
|
||||
; for p in $(VL_INST_INC_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/$$p; \
|
||||
done
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||
cd $(srcdir) \
|
||||
; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DESTDIR)$(pkgdatadir)/examples/$$p; \
|
||||
done
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgconfigdir)
|
||||
$(INSTALL_DATA) verilator.pc $(DESTDIR)$(pkgconfigdir)
|
||||
|
||||
VL_INST_DATA_FILES = verilator.1
|
||||
install: all_nomsg installbin installman installdata install-msg
|
||||
# We don't trust rm -rf, so rmdir instead as it will fail if user put in other files
|
||||
uninstall:
|
||||
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir)/bin && rm -f $(VL_INST_BIN_FILES)
|
||||
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_BLDDIR_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir) && rm -f $(VL_INST_INC_SRCDIR_FILES)
|
||||
-cd $(DESTDIR)$(pkgdatadir)/examples && rm -f $(VL_INST_DATA_SRCDIR_FILES)
|
||||
-rm $(DESTDIR)$(pkgconfigdir)/verilator.pc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/bin
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include/vltstd
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/include
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_c
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sc
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_sp
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples/test_v
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)/examples
|
||||
-rmdir $(DESTDIR)$(pkgdatadir)
|
||||
-rmdir $(DESTDIR)$(pkgconfigdir)
|
||||
|
||||
install: all_nomsg install-all
|
||||
install-all: installbin installman installdata install-msg
|
||||
|
||||
install-here: installman ftp
|
||||
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
DISTNAMEREV = $(shell sed -e '/DTVERSION/!d' -e 's/.*verilator_\([^"]*\).*/\1/' -e q ${srcdir}/src/config_rev.h)
|
||||
|
||||
DIRPROJECT := $(shell project_dir --project)
|
||||
VERILATOR_CAD_DIR = $(CAD_DIR)/verilator/$(DISTNAMEREV)/$(DIRPROJECT_ARCH)
|
||||
INST_PROJ_CVS = cp_if_cvs_diff
|
||||
|
||||
install-project: dist
|
||||
@echo "Install-project to $(DIRPROJECT)"
|
||||
strip verilator_bin*
|
||||
strip verilator_coverage_bin*
|
||||
$(MAKE) install-project-quick
|
||||
for p in verilator.1 ; do \
|
||||
$(INSTALL_PROGRAM) -m 0666 $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
|
||||
done
|
||||
$(INST_PROJ_CVS) $(DISTNAME).tgz $(DIRPROJECT)/hw/utils/verilator/verilator.tgz
|
||||
rm $(DISTNAME).tgz
|
||||
@@ -284,49 +379,82 @@ endif
|
||||
for p in $(INST_PROJ_BIN_FILES) ; do \
|
||||
$(INST_PROJ_CVS) $$p $(DIRPROJECT)/hw/utils/verilator/$$p-$(DIRPROJECT_ARCH); \
|
||||
done
|
||||
|
||||
install-cadtools: dist
|
||||
@echo "Install-project to $(CAD_DIR)"
|
||||
strip verilator_bin*
|
||||
strip verilator_coverage_bin*
|
||||
$(MAKE) install-cadtools-quick
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/man/man1
|
||||
for p in $(VL_INST_MAN_FILES) ; do \
|
||||
$(INSTALL_DATA) $$p $(VERILATOR_CAD_DIR)/man/man1/$$p; \
|
||||
done
|
||||
$(INST_PROJ_CVS) $(DISTNAME).tgz $(VERILATOR_CAD_DIR)/verilator.tgz
|
||||
rm $(DISTNAME).tgz
|
||||
|
||||
install-cadtools-quick:
|
||||
ifeq ($(CFG_WITH_DEFENV),yes)
|
||||
@echo "%Error: Reconfigure with './configure --disable-defenv' to avoid hardcoded paths."
|
||||
false
|
||||
endif
|
||||
@echo "Install-cadtools-quick (no strip) to $(VERILATOR_CAD_DIR)"
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/include/vltstd
|
||||
$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/bin
|
||||
for p in $(INST_PROJ_FILES) ; do \
|
||||
$(INST_PROJ_CVS) $$p $(VERILATOR_CAD_DIR)/$$p; \
|
||||
done
|
||||
for p in $(INST_PROJ_BIN_FILES) ; do \
|
||||
$(INST_PROJ_CVS) $$p $(VERILATOR_CAD_DIR)/$$p; \
|
||||
done
|
||||
|
||||
# VERILATOR_AUTHOR_SITE
|
||||
endif
|
||||
|
||||
# Use --xml flag to see the cppcheck code to use for suppression
|
||||
CPPCHECK = src/cppcheck_filtered
|
||||
CPPCHECK_FLAGS = --enable=all --inline-suppr \
|
||||
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList
|
||||
CPPCHECK_FLAGS += --xml
|
||||
CPPCHECK_CPP = $(wildcard $(srcdir)/include/*.cpp $(srcdir)/src/*.cpp)
|
||||
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CPPCHECK_CPP))
|
||||
CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
|
||||
|
||||
cppcheck: $(CPPCHECK_DEP)
|
||||
%.cppcheck: %.cpp
|
||||
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 $(CPPCHECK_INC) $<
|
||||
|
||||
ftp: info
|
||||
|
||||
install-msg:
|
||||
@echo "Installed!"
|
||||
@echo
|
||||
@echo "Add to your startup file (for bash or csh, as appropriate):"
|
||||
@echo " export VERILATOR_ROOT="`pwd`
|
||||
@echo " setenv VERILATOR_ROOT "`pwd` " ; export VERILATOR_ROOT "
|
||||
@echo
|
||||
@echo "See 'verilator.txt' for documentation."
|
||||
@echo "For documentation see 'man verilator' or 'verilator --help'"
|
||||
@echo "For forums and to report bugs see http://www.veripool.org/verilator"
|
||||
@echo
|
||||
|
||||
uninstall:
|
||||
-cd $(DESTDIR)$(mandir)/man1 && rm -f $(VL_INST_MAN_FILES)
|
||||
-cd $(DESTDIR)$(bindir) && rm -f $(VL_INST_BIN_FILES)
|
||||
-rm -f $(DESTDIR)$(pkgdatadir)
|
||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in
|
||||
|
||||
# autoheader might not change config_build.h.in, so touch a stamp file.
|
||||
IN_WILD := ${srcdir}/*.in ${srcdir}/*/*.in ${srcdir}/*/*/*.in \
|
||||
*.in */*.in */*.in
|
||||
|
||||
${srcdir}/config_build.h.in: stamp-h.in
|
||||
${srcdir}/stamp-h.in: configure.ac $(wildcard $(IN_WILD))
|
||||
# autoheader might not change config_build.h.in, so touch it
|
||||
${srcdir}/config_build.h: ${srcdir}/config_build.h.in configure
|
||||
cd ${srcdir} && autoheader
|
||||
echo timestamp > ${srcdir}/stamp-h.in
|
||||
config_build.h: stamp-h
|
||||
stamp-h: config_build.h.in config.status
|
||||
./config.status
|
||||
Makefile: Makefile.in config.status
|
||||
./config.status
|
||||
src/Makefile: src/Makefile.in config.status
|
||||
touch $@
|
||||
Makefile: Makefile.in config.status $(IN_WILD)
|
||||
./config.status
|
||||
src/Makefile: src/Makefile.in Makefile
|
||||
config.status: configure
|
||||
./config.status --recheck
|
||||
|
||||
configure: configure.ac
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
autoconf --warnings=all
|
||||
else
|
||||
autoconf
|
||||
endif
|
||||
|
||||
maintainer-clean::
|
||||
@echo "This command is intended for maintainers to use;"
|
||||
@echo "rebuilding the deleted files requires makeinfo."
|
||||
rm -f *.info* $(INFOS) faq.html verilator.html configure
|
||||
rm -f *.info* $(INFOS) configure
|
||||
|
||||
clean mostlyclean distclean maintainer-clean maintainer-copy::
|
||||
for dir in $(SUBDIRS); do \
|
||||
@@ -342,15 +470,21 @@ clean mostlyclean distclean maintainer-clean::
|
||||
rm -f *.tex
|
||||
|
||||
distclean maintainer-clean::
|
||||
rm -f Makefile config.status config.cache config.log verilator_bin* TAGS
|
||||
rm -f include/verilated.mk
|
||||
rm -f Makefile config.status config.cache config.log TAGS
|
||||
rm -f verilator_bin* verilator_coverage_bin*
|
||||
rm -f include/verilated.mk include/verilated_config.h
|
||||
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/[a-z]*.in \
|
||||
${srcdir}/[a-z]*.in ${srcdir}/*.texi
|
||||
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
|
||||
${srcdir}/*.in ${srcdir}/*.pod
|
||||
|
||||
TAGS: $(TAGFILES)
|
||||
etags $(TAGFILES)
|
||||
|
||||
.PHONY: doxygen
|
||||
|
||||
doxygen:
|
||||
$(DOXYGEN) doxygen.config
|
||||
|
||||
######################################################################
|
||||
# Test targets
|
||||
|
||||
@@ -362,14 +496,12 @@ dist-file-list:
|
||||
######################################################################
|
||||
# Distributions
|
||||
|
||||
DISTCONFIG = src/config_build.h.in
|
||||
|
||||
DISTTITLE := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e 's/v/V/' -e q $(DISTCONFIG))
|
||||
DISTNAME := $(shell sed -e '/DTVERSION/!d' -e 's/[^0-9]*\([0-9.a-z]*\).*/verilator-\1/' -e q $(DISTCONFIG))
|
||||
DISTDATEPRE := $(shell sed -e '/DTVERSION/!d' -e 's/.*\([1-2][0-9][0-9][0-9].[0-9]*[0-9].[0-9]*[0-9]\).*/\1/' -e q $(DISTCONFIG))
|
||||
DISTTITLE := Verilator $(word 1,$(PACKAGE_VERSION))
|
||||
DISTNAME := verilator-$(word 1,$(PACKAGE_VERSION))
|
||||
DISTDATEPRE := $(word 2,$(PACKAGE_VERSION))
|
||||
DISTDATE := $(subst /,-,$(DISTDATEPRE))
|
||||
|
||||
DISTTAGNAME := $(subst .,_,$(subst -,_,$(DISTNAME)))
|
||||
DISTDATE := $(subst /,-,$(DISTDATEPRE))
|
||||
|
||||
tag:
|
||||
svnorcvs tag $(DISTTAGNAME)
|
||||
|
||||
+201
@@ -0,0 +1,201 @@
|
||||
# DESCRIPTION: DOCUMENT source run through perl to produce README file
|
||||
# Use 'make README' to produce the output file
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
This is the Verilator package README file.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
http://www.veripool.org/verilator
|
||||
|
||||
This package is Copyright 2003-2017 by Wilson Snyder. (Report bugs to
|
||||
L<http://www.veripool.org/>.)
|
||||
|
||||
Verilator is free software; you can redistribute it and/or modify it under
|
||||
the terms of either the GNU Lesser General Public License Version 3 or the
|
||||
Perl Artistic License Version 2.0. (See the documentation for more
|
||||
details.)
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details.
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
Verilator converts synthesizable (generally not behavioral) Verilog code
|
||||
into C++ or SystemC code. It is not a complete simulator, just a
|
||||
translator.
|
||||
|
||||
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
|
||||
reads the specified Verilog code, lints it, and optionally adds coverage
|
||||
code. For C++ format, it outputs .cpp and .h files. For SystemC format,
|
||||
it outputs .cpp and .h files using the standard SystemC headers.
|
||||
|
||||
The resulting files are then compiled with C++. The user writes a little
|
||||
C++ wrapper file, which instantiates the top level module. This is
|
||||
compiled in C++, and linked with the Verilated files.
|
||||
|
||||
The resulting executable will perform the actual simulation.
|
||||
|
||||
=head1 SUPPORTED SYSTEMS
|
||||
|
||||
Verilator is developed and has primary testing on Ubuntu. Versions have
|
||||
also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It should run
|
||||
with minor porting on any Linix-ish platform. Verilator also works on
|
||||
Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
|
||||
output (not Verilator itself) compiles under MSVC++ 2008 and newer.
|
||||
|
||||
=head1 INSTALLATION
|
||||
|
||||
For more details see
|
||||
L<http://www.veripool.org/projects/verilator/wiki/Installing>.
|
||||
|
||||
If you will be modifying Verilator, you should use the "git" method as it
|
||||
will let you track changes.
|
||||
|
||||
=over 4
|
||||
|
||||
=item
|
||||
|
||||
The latest version is available at L<http://www.veripool.org/verilator>.
|
||||
|
||||
Download the latest package from that site, and decompress.
|
||||
|
||||
tar xvzf verilator_version.tgz
|
||||
|
||||
=item
|
||||
|
||||
If you will be using SystemC (vs straight C++ output), download SystemC
|
||||
from L<http://www.systemc.org>. Follow their installation instructions.
|
||||
You will need to set SYSTEMC_INCLUDE to point to the include directory with
|
||||
systemc.h in it, and SYSTEMC_LIBDIR to points to the directory with
|
||||
libsystemc.a in it. (Older installations may set SYSTEMC and SYSTEMC_ARCH
|
||||
instead.)
|
||||
|
||||
=item
|
||||
|
||||
You will need the C<flex> and C<bison> packages installed.
|
||||
|
||||
=item
|
||||
|
||||
C<cd> to the Verilator directory containing this README.
|
||||
|
||||
=item
|
||||
|
||||
You now have to decide how you're going to eventually install the kit.
|
||||
|
||||
Note Verilator builds the current value of VERILATOR_ROOT, SYSTEMC_INCLUDE,
|
||||
and SYSTEMC_LIBDIR as defaults into the executable, so try to have them
|
||||
correct before configuring.
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1.
|
||||
|
||||
Our personal favorite is to always run Verilator from the kit directory.
|
||||
This allows the easiest experimentation and upgrading. It's also how most
|
||||
EDA tools operate; to run you point to the tarball, no install is needed.
|
||||
|
||||
export VERILATOR_ROOT=`pwd` # if your shell is bash
|
||||
setenv VERILATOR_ROOT `pwd` # if your shell is csh
|
||||
./configure
|
||||
|
||||
=item 2.
|
||||
|
||||
To install globally onto a "cad" disk with multiple versions of every tool,
|
||||
and add it to path using Modules/modulecmd:
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
# For the tarball, use the version number instead of git describe
|
||||
./configure --prefix /CAD_DISK/verilator/`git describe | sed "s/verilator_//"`
|
||||
|
||||
After installing you'll want a module file like the following:
|
||||
|
||||
set install_root /CAD_DISK/verilator/{version-number-used-above}
|
||||
unsetenv VERILATOR_ROOT
|
||||
prepend-path PATH $install_root/bin
|
||||
prepend-path MANPATH $install_root/man
|
||||
prepend-path PKG_CONFIG_PATH $install_root/share/pkgconfig
|
||||
|
||||
=item 3.
|
||||
|
||||
The next option is to install it globally, using the normal system paths:
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
./configure
|
||||
|
||||
=item 4.
|
||||
|
||||
Alternatively you can configure a prefix that install will populate, as
|
||||
most GNU tools support:
|
||||
|
||||
unset VERILATOR_ROOT # if your shell is bash
|
||||
unsetenv VERILATOR_ROOT # if your shell is csh
|
||||
./configure --prefix /opt/verilator-VERSION
|
||||
|
||||
Then after installing you will need to add /opt/verilator-VERSION/bin to
|
||||
PATH.
|
||||
|
||||
=back
|
||||
|
||||
=item
|
||||
|
||||
Type C<make> to compile Verilator.
|
||||
|
||||
Type C<make test> to check the compilation.
|
||||
|
||||
Configure with C<--enable-longtests> for more complete developer tests.
|
||||
Additional packages may be required for these tests.
|
||||
|
||||
You may get a error about a typedef conflict for uint32_t. Edit
|
||||
verilated.h to change the typedef to work, probably to @samp{typedef
|
||||
unsigned long uint32_t;}.
|
||||
|
||||
=item
|
||||
|
||||
If you used the VERILATOR_ROOT scheme you're done. Programs should set the
|
||||
environment variable VERILATOR_ROOT to point to this distribution, then
|
||||
execute $VERILATOR_ROOT/bin/verilator, which will find the path to all
|
||||
needed files.
|
||||
|
||||
If you used the prefix scheme, now do a C<make install>. To run verilator,
|
||||
have the verilator binary directory in your PATH (this should already be
|
||||
true if using the default configure), and make sure VERILATOR_ROOT is not
|
||||
set.
|
||||
|
||||
=back
|
||||
|
||||
=head1 USAGE DOCUMENTATION
|
||||
|
||||
Detailed documentation and the man page can be seen by running:
|
||||
|
||||
bin/verilator --help
|
||||
|
||||
or reading verilator.txt in the same directory as this README.
|
||||
|
||||
=head1 DIRECTORY STRUCTURE
|
||||
|
||||
The directories in the kit after de-taring are as follows:
|
||||
|
||||
bin/verilator => Compiler Wrapper invoked to Verilate code
|
||||
include/ => Files that should be in your -I compiler path
|
||||
include/verilated*.cpp => Global routines to link into your simulator
|
||||
include/verilated*.h => Global headers
|
||||
include/verilated.v => Stub defines for linting
|
||||
include/verilated.mk => Common makefile
|
||||
src/ => Translator source code
|
||||
test_v => Example Verilog code for other test dirs
|
||||
test_c => Example Verilog->C++ conversion
|
||||
test_sc => Example Verilog->SystemC conversion
|
||||
test_verilated => Internal tests
|
||||
test_regress => Internal tests
|
||||
|
||||
=head1 LIMITATIONS
|
||||
|
||||
See verilator.txt (or execute C<bin/verilator --help>) for limitations.
|
||||
@@ -1,154 +1,129 @@
|
||||
// DESCRIPTION: Verilator: List of To Do issues.
|
||||
//
|
||||
// Copyright 2004-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2004-2017 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.
|
||||
|
||||
|
||||
Features:
|
||||
Finish 3.400 new ordering fixes
|
||||
Latch optimizations {Need here}
|
||||
Task I/Os connecting to non-simple variables.
|
||||
Fix nested casez statements expanding into to huge C++. [JeanPaul Vanitegem]
|
||||
Fix FileLine memory inefficiency
|
||||
Fix ordering of each bit separately in a signal (mips)
|
||||
Language support:
|
||||
* Fix ordering of each bit separately in a signal (mips)
|
||||
assign b[3:0] = b[7:4]; assign b[7:4] = in;
|
||||
Support gate primitives/ cell libraries from xilinx, etc
|
||||
Assign dont_care value to an 1'bzzz assignment
|
||||
Function to eval combo logic after /*verilator public*/ functions [gwaters]
|
||||
Support generated clocks (correctness)
|
||||
?gcov coverage
|
||||
Selectable SystemC types based on widths (see notes below)
|
||||
Compile time
|
||||
Inline first level trace routines
|
||||
Coverage
|
||||
Points should be per-scope like everything else rather then per-module
|
||||
Expression coverage (see notes)
|
||||
Constant functions for widths, etc, IE "input [log2(PARAM):0] xx;"
|
||||
More Verilog 2001 Support
|
||||
(* *) Attributes (just ignore -- preprocessor?)
|
||||
Real numbers (NEVER)
|
||||
Recursive functions (NEVER)
|
||||
Verilog configuration files (NEVER)
|
||||
DPI to define C/C++ calls from Verilog
|
||||
* Support UDP gate primitives/ cell libraries
|
||||
(have code for combos - problem is sequential udps)
|
||||
* Function to eval combo logic after /*verilator public*/ functions [gwaters]
|
||||
* Support generated clocks (correctness)
|
||||
* Real numbers
|
||||
* Recursive functions
|
||||
* Verilog configuration files
|
||||
* Structs/unions (have starting point)
|
||||
* DPI to define C/C++ calls from Verilog
|
||||
* Expression coverage (see notes)
|
||||
* Better tristate support
|
||||
|
||||
Long-term Features
|
||||
Assertions
|
||||
VHDL parser [Philips]
|
||||
Tristate support
|
||||
SystemPerl integration
|
||||
Multithreaded execution
|
||||
Front end parser integration into Verilog-Perl like Netlist
|
||||
* Assertions
|
||||
* Tristate support
|
||||
* Multithreaded execution
|
||||
|
||||
Configure/Make/Install
|
||||
* Full MSVC++ compilation (does scons support this?) (4.000?)
|
||||
* Distribute with flex/bison already expanded?
|
||||
Flex library not needed. Probably too difficult to be worth it.
|
||||
|
||||
Testing:
|
||||
Capture all inputs into global "rerun it" file
|
||||
Code to make wrapper that sets signals, so can do comparison checks
|
||||
New random program generator
|
||||
Better graph viewer with search and zoom
|
||||
Port and test against opencores.org code
|
||||
* Move test_c/sp/v/verilated into test_regress format (4.000?)
|
||||
* Capture all inputs into global "rerun it" file
|
||||
* Code to make wrapper that sets signals, so can do comparison checks
|
||||
* New random program generator
|
||||
* Better graph viewer with search and zoom
|
||||
* Port and test against opencores.org code
|
||||
* // verilator debug in code so can see only tree affecting those nodes
|
||||
|
||||
Usability:
|
||||
Better reporting of unopt problems, including what lines of code
|
||||
Report more errors (all of them?) before exiting [Eugene Weber]
|
||||
* Detect and pre-remove most UNOPTFLATs (4.000)
|
||||
* Better reporting of unopt problems, including what lines of code
|
||||
* Report more errors (all of them?) before exiting [Eugene Weber]
|
||||
* Auto-create scons config files
|
||||
* Print version/etc message at runtime. (4.000?)
|
||||
Include number of lines of code, percent comments, code complexity measurement
|
||||
<-80chars------------------------------------------------------------------->
|
||||
Verilator 3.600 - fast, free, open-sourced. Copyright 2001-2013.
|
||||
Verilated #### modules, #### instances, ##### sigs,
|
||||
#### non-comment lines, ##### ops, ### KB model size
|
||||
* Default the --l2name to remove extra "v" level of hierarchy (flag to make "top")
|
||||
|
||||
Lint:
|
||||
* CDCRSTLOGIC should allow filtering with paths
|
||||
"waive CDCRSTLOGIC --from a.b.sig --to a.c.sig --via OR"
|
||||
|
||||
Internal Code:
|
||||
Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
||||
and removing it will speed up and simplify all the other code.
|
||||
V3Graph should be templated container type, taking in Vertex + Edge types
|
||||
* Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
||||
and removing it will speed up and simplify all the other code.
|
||||
* V3Graph should be templated container type, taking in Vertex + Edge types
|
||||
* Rename V3PreLex etc to match VerilogPerl filenames
|
||||
* Instead of string, have an VEncodedString/VIdString which contains __DOT__ish
|
||||
things, to reduce bugs. Also add _20 trailing space to \ encoded names. (4.000)
|
||||
|
||||
Runtime:
|
||||
* New evalulation loop ~/src/verilator/notes/event_loop.txt (4.000?)
|
||||
* Remove all private internal functions from top level wrapper header, move
|
||||
to new level (4.000?)
|
||||
* Completely standalone simulation (4.000)
|
||||
main() records arguments for $test$plusvars
|
||||
instantiates top,
|
||||
does tracing (support $dump?)
|
||||
calls top->simulateForever()
|
||||
exits
|
||||
|
||||
Performance:
|
||||
Constant propagation
|
||||
* Latch optimizations
|
||||
* Constant propagation
|
||||
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF))
|
||||
Extra shift (perhaps due to clean): if (1 & CAST (VARREF >> #))
|
||||
Gated clock and latch conversion to flops. [JeanPaul Vanitegem]
|
||||
* Gated clock and latch conversion to flops. [JeanPaul Vanitegem]
|
||||
Could propagate the AND into pos/negedges and let domaining optimize.
|
||||
Negedge reset
|
||||
* Negedge reset
|
||||
Switch to remove negedges that don't matter
|
||||
Can't remove async resets from control flops (like in syncronizers)
|
||||
If all references to array have a constant index, blow up into separate signals-per-index
|
||||
Multithreaded execution
|
||||
Bit-multiply for faster bit swapping and a=b[1,3,2] random bit reorderings.
|
||||
Move _last sets and all other combo logic inside master
|
||||
* If all references to array have a constant index, blow up into separate signals-per-index
|
||||
* Bit-multiply for faster bit swapping and a=b[1,3,2] random bit reorderings.
|
||||
* Move _last sets and all other combo logic inside master
|
||||
if() that triggers on all possible sense items
|
||||
Rewrite and combine V3Life, V3Subst
|
||||
* Rewrite and combine V3Life, V3Subst
|
||||
If block temp only ever set in one place to constant, propagate it
|
||||
Used in t_mem for array delayed assignments
|
||||
Replace variables if set later in same cfunc branch
|
||||
See for example duplicate sets of _narrow in cycle 90/91 of t_select_plusloop
|
||||
Same assignment on both if branches
|
||||
* Same assignment on both if branches
|
||||
"if (a) { ... b=2; } else { ... b=2;}" -> "b=2; if ..."
|
||||
Careful though, as b could appear in the statement or multiple times in statement
|
||||
(Could just require exatly two 'b's in statement)
|
||||
Simplify XOR/XNOR/AND/OR bit selection trees
|
||||
* Simplify XOR/XNOR/AND/OR bit selection trees
|
||||
Foo = A[1] ^ A[2] ^ A[3] etc are better as ^ ( A & 32'b...1110 )
|
||||
Combine variables into wider elements
|
||||
* Combine variables into wider elements
|
||||
Parallel statements on different bits should become single signal
|
||||
Variables that are always consumed in "parallel" can be joined
|
||||
Duplicate assignments in gate optimization
|
||||
* Duplicate assignments in gate optimization
|
||||
Common to have many separate posedge blocks, each with identical
|
||||
reset_r <= rst_in
|
||||
*If signal is used only once (not counting trace), always gate substitute
|
||||
* If signal is used only once (not counting trace), always gate substitute
|
||||
Don't merge if any combining would form circ logic (out goes back to in)
|
||||
Multiple assignments each bit can become single assign with concat
|
||||
* Multiple assignments each bit can become single assign with concat
|
||||
Make sure a SEL of a CONCAT can get the single bit back.
|
||||
Usually blocks/values
|
||||
* Usually blocks/values
|
||||
Enable only after certain time, so VL_TIME_I(32) > 0x1e gets eliminated out
|
||||
Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
||||
Allow Split of case statements without a $display/$stop
|
||||
I-cache packing improvements (what/how?)
|
||||
Data cache organization (order of vars in class)
|
||||
* Better ordering of a<=b, b<=c, put all refs to 'b' next to each other to optimize caching
|
||||
* Allow Split of case statements without a $display/$stop
|
||||
* I-cache packing improvements (what/how?)
|
||||
* Data cache organization (order of vars in class)
|
||||
First have clocks,
|
||||
then bools instead of uint32_t's
|
||||
then based on what sense list they come from, all outputs, then all inputs
|
||||
finally have any signals part of a "usually" block, or constant.
|
||||
Rather then tracking widths, have a MSB...LSB of this expression
|
||||
* Rather then tracking widths, have a MSB...LSB of this expression
|
||||
(or better, a bitmask of bits relevant in this expression)
|
||||
Track recirculation and convert into clock-enables
|
||||
Clock enables should become new clocking domains for speed
|
||||
If floped(a) & flopped(b) and no other a&b, then instead flop(a&b).
|
||||
Sort by output bitselects so can combine more assignments (see DDP example dx_dm signal)
|
||||
|
||||
All of the temp vars that get set, exp pre_ vars and never feedback
|
||||
(not flops) don't need to be stored in the structs, but instead can
|
||||
be per-invocation, and even better register-colored-like to reuse
|
||||
the space. This will greatly reduce the data footprint.
|
||||
|
||||
|
||||
//**********************************************************************
|
||||
//* Detailed notes on 'todo' features
|
||||
|
||||
Selectable SystemC types based on widths (see notes below)
|
||||
Statements:
|
||||
verilator sc_type uint32_t {override specific I/O signals}
|
||||
verilator sc_typedef width 1 bool
|
||||
verilator sc_typedef width 2-32 uint32_t
|
||||
verilator sc_typedef width 33-64 uint64_t
|
||||
verilator sc_typedef width 65+ sc_bv<width> //<< programmable width
|
||||
Replace `systemc_clock, --pins64
|
||||
Have accessor function with type overloading to get or set the pin value.
|
||||
(Get rid of getdatap mess?)
|
||||
|
||||
//**********************************************************************
|
||||
//* Eventual tristate bus Stuff allowed (old verilator)
|
||||
|
||||
1) Tristate assignments must be continuous assignments
|
||||
The RHS of a tristate assignment can be the following
|
||||
a) a node (tristate or non-tristate)
|
||||
b) a constant (must be all or no z's)
|
||||
x'b0, x'bz, x{x'bz}, x{x'b0} -> are allowed
|
||||
c) a conditional whose possible values are (a) or (b)
|
||||
|
||||
2) One can lose that fact that a node is a tristate node. This happens
|
||||
if a tristate node is assigned to a 'standard' node, or is used on
|
||||
RHS of a conditional. The following infer tristate signals:
|
||||
a) inout <SIGNAL>
|
||||
b) tri <SIGNAL>
|
||||
c) assigning to 'Z' (maybe through a conditional)
|
||||
Note: tristate-ness of an output port determined only by
|
||||
statements in the module (not the instances it calls)
|
||||
|
||||
4) Tristate variables can't be multidimensional arrays
|
||||
5) Only check tristate contention between modules (not within!)
|
||||
6) Only simple compares with 'Z' are allowed (===)
|
||||
|
||||
* Track recirculation and convert into clock-enables
|
||||
* Clock enables should become new clocking domains for speed
|
||||
* If floped(a) & flopped(b) and no other a&b, then instead flop(a&b).
|
||||
* Sort by output bitselects so can combine more assignments (see DDP example dx_dm signal)
|
||||
|
||||
+2106
-676
File diff suppressed because it is too large
Load Diff
Executable
+291
@@ -0,0 +1,291 @@
|
||||
: # -*-Mode: perl;-*- use perl, wherever it is
|
||||
eval 'exec perl -wS $0 ${1+"$@"}'
|
||||
if 0;
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2003-2017 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.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
######################################################################
|
||||
|
||||
require 5.006_001;
|
||||
use warnings;
|
||||
BEGIN {
|
||||
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
|
||||
# Magic to allow author testing of perl packages in local directory
|
||||
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
|
||||
}
|
||||
}
|
||||
|
||||
use Getopt::Long;
|
||||
use FindBin qw($RealBin $RealScript);
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use Cwd qw(abs_path getcwd);
|
||||
|
||||
use strict;
|
||||
use vars qw ($Debug @Opt_Verilator_Sw);
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
# main
|
||||
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
|
||||
$Debug = 0;
|
||||
|
||||
# No arguments can't do anything useful. Give help
|
||||
if ($#ARGV < 0) {
|
||||
pod2usage(-exitstatus=>2, -verbose=>0);
|
||||
}
|
||||
|
||||
# We sneak a look at the flags so we can do some pre-environment checks
|
||||
# All flags will hit verilator...
|
||||
foreach my $sw (@ARGV) {
|
||||
$sw = "'$sw'" if $sw =~ m![^---a-zA-Z0-9_/\\:.+]!;
|
||||
push @Opt_Verilator_Sw, $sw;
|
||||
}
|
||||
|
||||
Getopt::Long::config ("no_auto_abbrev","pass_through");
|
||||
if (! GetOptions (
|
||||
# Major operating modes
|
||||
"help" => \&usage,
|
||||
"debug:s" => \&debug,
|
||||
# "version!" => \&version, # Also passthru'ed
|
||||
# Additional parameters
|
||||
"<>" => sub {}, # Ignored
|
||||
)) {
|
||||
pod2usage(-exitstatus=>2, -verbose=>0);
|
||||
}
|
||||
|
||||
# Normal, non gdb
|
||||
run (verilator_coverage_bin()
|
||||
." ".join(' ',@Opt_Verilator_Sw));
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
}
|
||||
|
||||
sub debug {
|
||||
shift;
|
||||
my $level = shift;
|
||||
$Debug = $level||3;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
# Builds
|
||||
|
||||
sub verilator_coverage_bin {
|
||||
my $bin = "";
|
||||
# Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
|
||||
my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
|
||||
|| "verilator_coverage_bin_dbg");
|
||||
if (defined($ENV{VERILATOR_ROOT})) {
|
||||
my $dir = $ENV{VERILATOR_ROOT};
|
||||
if (-x "$dir/bin/$basename") { # From a "make install" into VERILATOR_ROOT
|
||||
$bin = "$dir/bin/$basename";
|
||||
} else {
|
||||
$bin = "$dir/$basename"; # From pointing to kit directory
|
||||
}
|
||||
} else {
|
||||
if (-x "$RealBin/$basename") {
|
||||
$bin = "$RealBin/$basename"; # From path/to/verilator with verilator_bin installed
|
||||
} else {
|
||||
$bin = $basename; # Find in PATH
|
||||
}
|
||||
# Note we don't look under bin/$basename which would be right if running
|
||||
# in the kit dir. Running that would likely break, since
|
||||
# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
|
||||
}
|
||||
return $bin;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
# Utilities
|
||||
|
||||
sub run {
|
||||
# Run command, check errors
|
||||
my $command = shift;
|
||||
$! = undef; # Cleanup -x
|
||||
print "\t$command\n" if $Debug>=3;
|
||||
system($command);
|
||||
my $status = $?;
|
||||
if ($status) {
|
||||
if ($! =~ /no such file or directory/i) {
|
||||
warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
|
||||
}
|
||||
if ($Debug) { # For easy rerunning
|
||||
warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
|
||||
warn "%Error: $command\n";
|
||||
}
|
||||
if ($status & 127) {
|
||||
if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
|
||||
warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
|
||||
} elsif (($status & 127) == 6) { # SIGABRT
|
||||
warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
|
||||
} else {
|
||||
warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
|
||||
}
|
||||
}
|
||||
die "%Error: Command Failed $command\n";
|
||||
}
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
#######################################################################
|
||||
package main;
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
verilator_coverage - Verilator coverage analyzer
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
verilator_coverage --help
|
||||
verilator_coverage --version
|
||||
|
||||
verilator_coverage --annotate <obj>
|
||||
|
||||
verilator_coverage -write merged.dat -read <datafiles>...
|
||||
|
||||
Verilator_coverage processes Verilator coverage reports.
|
||||
|
||||
With --anotate, it reads the specified data file and generates annotated
|
||||
source code with coverage metrics annotated. If multiple coverage points
|
||||
exist on the same line, additional lines will be inserted to report the
|
||||
additional points.
|
||||
|
||||
Additional Verilog-standard arguments specify the search paths necessary to
|
||||
find the source code that the coverage analysis was performed on.
|
||||
|
||||
To get correct coverage percentages, you may wish to read logs/coverage.pl
|
||||
into Emacs and do a M-x keep-lines to include only those statistics of
|
||||
interest.
|
||||
|
||||
For Verilog conditions that should never occur, you should add a $stop
|
||||
statement. This will remove the coverage during the next build.
|
||||
|
||||
=head1 ARGUMENTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item I<filename>
|
||||
|
||||
Specify input data file, may be repeated to read multiple inputs. If no
|
||||
data file is specified, by default coverage.dat is read.
|
||||
|
||||
=item --annotate I<output_directory>
|
||||
|
||||
Sprcifies the directory name that source files with annotated coverage data
|
||||
should be written to.
|
||||
|
||||
=item --annotate-all
|
||||
|
||||
Specifies all files should be shown. By default, only those source files
|
||||
which have low coverage are written to the output directory.
|
||||
|
||||
=item --annotate-min I<count>
|
||||
|
||||
Specifies the minimum occurrence count that should be flagged if the
|
||||
coverage point does not include a specified threshold. Defaults to 10.
|
||||
|
||||
=item --help
|
||||
|
||||
Displays this message and program version and exits.
|
||||
|
||||
=item --rank
|
||||
|
||||
Print an experimental report listing the relative importance of each test
|
||||
in covering all of the coverage points. The report shows "Covered" which
|
||||
indicates the number of points that test covers; a test is considered to
|
||||
cover a point if it has a bucket count of at least 1. The "rank" column has
|
||||
a higher number t indicate the test is more important, and rank 0 means the
|
||||
test does not need to be run to cover the points. "RankPts" indicates the
|
||||
number of coverage points this test will contribute to overall coverage if
|
||||
all tests are run in the order of highest to lowest rank.
|
||||
|
||||
=item --unlink
|
||||
|
||||
When using --write to combine coverage data, unlink all input files after
|
||||
the output has been created.
|
||||
|
||||
=item --version
|
||||
|
||||
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.
|
||||
|
||||
=back
|
||||
|
||||
=head1 VERILOG ARGUMENTS
|
||||
|
||||
The following arguments are compatible with GCC, VCS and most Verilog
|
||||
programs.
|
||||
|
||||
=over 4
|
||||
|
||||
=item +libext+I<ext>+I<ext>...
|
||||
|
||||
Defines the extensions for Verilog files.
|
||||
|
||||
=item +define+I<var>+I<value>
|
||||
=item -DI<var>=I<value>
|
||||
|
||||
Defines the given variable.
|
||||
|
||||
=item +incdir+I<dir>
|
||||
=item -II<dir>
|
||||
|
||||
Specifies a directory for finding include files.
|
||||
|
||||
=item -f I<file>
|
||||
|
||||
Specifies a file containing additional command line arguments.
|
||||
|
||||
=item -y I<dir>
|
||||
|
||||
Specifies a module search directory.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
The latest version is available from L<http://www.veripool.org/>.
|
||||
|
||||
Copyright 2003-2017 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify the Verilator internals under the terms of
|
||||
either the GNU Lesser General Public License Version 3 or the Perl Artistic
|
||||
License Version 2.0.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
C<verilator>
|
||||
|
||||
L<verilator_coverage --help> which is the source for this document.
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
+69
-8
@@ -14,6 +14,19 @@ use vars qw ($Debug);
|
||||
|
||||
#======================================================================
|
||||
|
||||
# Old version 1 dump nodes with no dtypep's
|
||||
our %Ver1_Non_Dtyped = map {$_ => 1} qw(
|
||||
ACTIVE ALWAYS ALWAYSPOST ALWAYSPUBLIC ATTROF BEGIN BREAK CASE CASEITEM
|
||||
CCALL CELL CELLINLINE CFILE CFUNC CHANGEDET CLOCKING COMMENT CONTINUE
|
||||
COVERDECL COVERINC COVERTOGGLE CRETURN CSTMT DEFPARAM DISABLE DISPLAY DOT
|
||||
DPIEXPORT FCLOSE FFLUSH FINAL FINISH FOPEN GENCASE GENERATE GENFOR GENIF
|
||||
IF IMPLICIT INITARRAY INITIAL JUMPGO JUMPLABEL MODULE NETLIST
|
||||
NOTFOUNDMODULE PACKAGE PACKAGEIMPORT PARSEREF PIN PORT PRAGMA PRIMITIVE
|
||||
PSLASSERT PSLCOVER PSLDEFCLOCK PULL RANGE READMEM REPEAT RETURN SCCTOR
|
||||
SCDTOR SCHDR SCIMP SCIMPHDR SCINT SCOPE SELBIT SELEXTRACT SELMINUS
|
||||
SELPLUS SENGATE SENITEM SENTREE SFORMAT SFORMATF STOP SYSIGNORE SYSTEMT
|
||||
TASK TASKREF TEXT TOPSCOPE TYPEDEFFWD TYPETABLE UCSTMT UDPTABLE
|
||||
UDPTABLELINE UNTILSTABLE VASSERT WHILE );
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
@@ -62,6 +75,7 @@ sub diff_dir {
|
||||
(my $base = $fn) =~ s!.*/!!;
|
||||
$files{$base}{b} = $fn;
|
||||
}
|
||||
my $any;
|
||||
foreach my $base (sort (keys %files)) {
|
||||
my $a = $files{$base}{a};
|
||||
my $b = $files{$base}{b};
|
||||
@@ -69,34 +83,81 @@ sub diff_dir {
|
||||
print "="x70,"\n";
|
||||
print "= $a <-> $b\n";
|
||||
diff_file($a,$b);
|
||||
$any = 1;
|
||||
}
|
||||
$any or warn "%Warning: No .tree files found\n";
|
||||
}
|
||||
|
||||
sub diff_file {
|
||||
my $a = shift;
|
||||
my $b = shift;
|
||||
# Compare the two tree files
|
||||
my $tmp_a = "/tmp/$$.a";
|
||||
my $tmp_b = "/tmp/$$.b";
|
||||
(my $short_a = $a) =~ s/[^a-zA-Z0-9.]+/_/g;
|
||||
(my $short_b = $b) =~ s/[^a-zA-Z0-9.]+/_/g;
|
||||
my $tmp_a = "/tmp/${$}_${short_a}.a";
|
||||
my $tmp_b = "/tmp/${$}_${short_b}.b";
|
||||
|
||||
filter ($a, $tmp_a);
|
||||
filter ($b, $tmp_b);
|
||||
my $vera = version_from($a);
|
||||
my $verb = version_from($b);
|
||||
my $verCvt = (($vera < 0x3900 && $verb >= 0x3900)
|
||||
|| ($vera >= 0x3900 && $verb < 0x3900));
|
||||
|
||||
filter ($a, $tmp_a, $verCvt);
|
||||
filter ($b, $tmp_b, $verCvt);
|
||||
system("diff -u $tmp_a $tmp_b");
|
||||
unlink $tmp_a;
|
||||
unlink $tmp_b;
|
||||
}
|
||||
|
||||
sub version_from {
|
||||
my $fn = shift;
|
||||
# Return dump format
|
||||
my $f1 = IO::File->new ($fn) or die "%Error: $! $fn,";
|
||||
while (defined (my $line=$f1->getline())) {
|
||||
last if $. > 10;
|
||||
return hex $1 if $line =~ /\(format (0x[0-9.]+)\)/;
|
||||
}
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
sub filter {
|
||||
my $fn1 = shift;
|
||||
my $fn2 = shift;
|
||||
my $verCvt = shift;
|
||||
# Remove hex numbers before diffing
|
||||
my $f1 = IO::File->new ($fn1) or die "%Error: $! $fn1,";
|
||||
my $f2 = IO::File->new ($fn2,"w") or die "%Error: $! $fn2,";
|
||||
while (defined (my $line=$f1->getline())) {
|
||||
same_line:
|
||||
next if $line =~ / This=/;
|
||||
$line =~ s/0x[a-f0-9]+/0x/g;
|
||||
$line =~ s/<e[0-9]+\#?>/<e>/g;
|
||||
$line =~ s/{\d+}/{}/g if !$Opt_Lineno;
|
||||
$line =~ s/{[a-z]*\d+}/{}/g if !$Opt_Lineno;
|
||||
if ($verCvt) {
|
||||
next if $line =~ /^ NETLIST/;
|
||||
$line =~ s!\@dt=0x\(G?/?([^)]+)\)!$1!g; # NEW: @dt -> OLD: non @dt format
|
||||
# # Below Ver1_Non_Dtyped may replace above further
|
||||
if ($line =~ /: ([A-Z]+) /) {
|
||||
my $type = $1;
|
||||
next if $type =~ 'DTYPE';
|
||||
if ($type eq 'TYPETABLE' || $type eq 'RANGE') {
|
||||
$line =~ /^(\s+\S+:) /; my $prefix = $1;
|
||||
while (defined ($line=$f1->getline())) {
|
||||
next if $line =~ /^\s+[a-z]/; # Table body
|
||||
next if $line =~ /^${prefix}[0-9]:/;
|
||||
goto same_line;
|
||||
}
|
||||
next;
|
||||
}
|
||||
if ($Ver1_Non_Dtyped{$type}) {
|
||||
$line =~ s! w[0-9]+!!g;
|
||||
}
|
||||
}
|
||||
$line =~ s!\@dt=0$!NoW!g; # NEW: dt=null -> common format
|
||||
$line =~ s!\@dt=0 !NoW !g; # NEW: dt=null -> common format
|
||||
$line =~ s! s?w0$! NoW!g; # OLD: no width -> common format
|
||||
$line =~ s! s?w0 ! NoW !g; # OLD: no width -> common format
|
||||
}
|
||||
print $f2 $line;
|
||||
}
|
||||
$f1->close;
|
||||
@@ -106,7 +167,7 @@ sub filter {
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -174,7 +235,7 @@ Do not show differences in line numbering.
|
||||
|
||||
The latest version is available from L<http://www.veripool.org/verilator>.
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. This package is free software; you can
|
||||
Copyright 2005-2017 by Wilson Snyder. This package is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
@@ -190,5 +251,5 @@ C<verilator>
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "$V4/bin/verilator_difftree $V4/test_c/obj_dir/V*_03_*.tree $V4N/test_c/obj_dir/V*_03_*.tree"
|
||||
### compile-command: "$V4/bin/verilator_difftree {$V4D,$V4}/test_regress/obj_dir/t_EXAMPLE/V*_03_*.tree"
|
||||
### End:
|
||||
|
||||
@@ -3,13 +3,18 @@ eval 'exec perl -wS $0 ${1+"$@"}'
|
||||
if 0;
|
||||
# DESCRIPTION: Print include statements for each ARGV
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This package is free software; you can
|
||||
# Copyright 2003-2017 by Wilson Snyder. This package is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
######################################################################
|
||||
|
||||
require 5.005;
|
||||
use warnings;
|
||||
print "// DESCR"."IPTION: Generated by verilator_includer via makefile\n";
|
||||
foreach my $param (@ARGV) {
|
||||
print "#include \"$param\"\n"
|
||||
if ($param =~ /^-D([^=]+)=(.*)/) {
|
||||
print "#define $1 $2\n"
|
||||
} else {
|
||||
print "#include \"$param\"\n"
|
||||
}
|
||||
}
|
||||
|
||||
+17
-3
@@ -39,7 +39,7 @@ profcfunc($Opt_File);
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -118,6 +118,18 @@ sub profcfunc {
|
||||
$groups{type}{"Common code under $design"} += $pct;
|
||||
$groups{design}{$design} += $pct;
|
||||
$groups{module}{$design." common code"} += $pct;
|
||||
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|
||||
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|
||||
|| $func =~ /^verilated/i) {
|
||||
$vfunc = sprintf("VLib %s", $func);
|
||||
$groups{type}{'VLib'} += $pct;
|
||||
$groups{design}{'VLib'} += $pct;
|
||||
$groups{module}{'VLib'} += $pct;
|
||||
} elsif ($func =~ /^_mcount_private/) {
|
||||
$vfunc = sprintf("Prof %s", $func);
|
||||
$groups{type}{'Prof'} += $pct;
|
||||
$groups{design}{'Prof'} += $pct;
|
||||
$groups{module}{'Prof'} += $pct;
|
||||
} else {
|
||||
$vfunc = sprintf("C++ %s", $func);
|
||||
$groups{type}{'C++'} += $pct;
|
||||
@@ -129,7 +141,7 @@ sub profcfunc {
|
||||
}
|
||||
|
||||
|
||||
foreach my $type qw(type design module) {
|
||||
foreach my $type (qw(type design module)) {
|
||||
my $missing = 100;
|
||||
foreach (sort (keys %{$groups{$type}})) {
|
||||
$missing -= $groups{$type}{$_};
|
||||
@@ -150,8 +162,10 @@ sub profcfunc {
|
||||
print("Verilog code profile:\n");
|
||||
print(" These are split into three categories:\n");
|
||||
print(" C++: Time in non-Verilated C++ code\n");
|
||||
print(" Prof: Time in profile overhead\n");
|
||||
print(" VBlock: Time attributable to a block in a Verilog file and line\n");
|
||||
print(" VCommon: Time in a Verilated module, due to all parts of the design\n");
|
||||
print(" VLib: Time in Verilated common libraries, called by the Verilated code\n");
|
||||
print("\n");
|
||||
|
||||
print(" % cumulative self \n");
|
||||
@@ -208,7 +222,7 @@ Displays this message and program version and exits.
|
||||
|
||||
The latest version is available from L<http://www.veripool.org/>.
|
||||
|
||||
Copyright 2007-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
Copyright 2007-2017 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
+152
-32
@@ -1,36 +1,88 @@
|
||||
dnl DESCRIPTION: Process this file with autoconf to produce a configure script.
|
||||
dnl
|
||||
dnl Copyright 2003-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
dnl redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
dnl General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
# DESCRIPTION: Process this file with autoconf to produce a configure script.
|
||||
#
|
||||
# Copyright 2003-2017 by Wilson Snyder. Verilator is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||
#AC_INIT([Verilator],[#.### devel])
|
||||
AC_INIT([Verilator],[3.912 2017-09-23])
|
||||
# When releasing, also update header of Changes file
|
||||
# and commit using "devel release" or "Version bump" message
|
||||
|
||||
AC_INIT(src/Verilator.cpp)
|
||||
AC_CONFIG_HEADER(src/config_build.h)
|
||||
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h verilator.pc)
|
||||
|
||||
dnl Special Substitutions
|
||||
AC_ARG_ENABLE(defenv,
|
||||
[AS_HELP_STRING([--disable-defenv], [disable hardcoded default environment variables])],
|
||||
CFG_WITH_DEFENV=$enableval,
|
||||
CFG_WITH_DEFENV=yes)
|
||||
AC_MSG_RESULT([configuring for $PACKAGE_STRING])
|
||||
|
||||
# Special Substitutions - CFG_WITH_DEFENV
|
||||
AC_MSG_CHECKING(whether to use hardcoded paths)
|
||||
AC_ARG_ENABLE([defenv],
|
||||
[AS_HELP_STRING([--disable-defenv],
|
||||
[disable using some hardcoded data paths extracted from some default environment variables (the default is to use hardcoded paths)])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_DEFENV=yes ;;
|
||||
no) CFG_WITH_DEFENV=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --disable-defenv]) ;;
|
||||
esac],
|
||||
CFG_WITH_DEFENV=yes)
|
||||
AC_SUBST(CFG_WITH_DEFENV)
|
||||
AC_MSG_RESULT($CFG_WITH_DEFENV)
|
||||
|
||||
dnl Compiler flags
|
||||
CXX=g++
|
||||
# Special Substitutions - CFG_WITH_CCWARN
|
||||
AC_MSG_CHECKING(whether to show and stop on compilation warnings)
|
||||
AC_ARG_ENABLE([ccwarn],
|
||||
[AS_HELP_STRING([--enable-ccwarn],
|
||||
[enable showing and stopping on compilation warnings])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_CCWARN=yes ;;
|
||||
no) CFG_WITH_CCWARN=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-ccwarn]) ;;
|
||||
esac],
|
||||
[case "x${VERILATOR_AUTHOR_SITE}" in
|
||||
x) CFG_WITH_CCWARN=no ;;
|
||||
*) CFG_WITH_CCWARN=yes ;;
|
||||
esac]
|
||||
)
|
||||
AC_SUBST(CFG_WITH_CCWARN)
|
||||
AC_MSG_RESULT($CFG_WITH_CCWARN)
|
||||
|
||||
# Special Substitutions - CFG_WITH_LONGTESTS
|
||||
AC_MSG_CHECKING(whether to run long tests)
|
||||
AC_ARG_ENABLE([longtests],
|
||||
[AS_HELP_STRING([--enable-longtests],
|
||||
[enable running long developer tests])],
|
||||
[case "${enableval}" in
|
||||
yes) CFG_WITH_LONGTESTS=yes ;;
|
||||
no) CFG_WITH_LONGTESTS=no ;;
|
||||
*) AC_MSG_ERROR([bad value ${enableval} for --enable-longtests]) ;;
|
||||
esac],
|
||||
[case "x${VERILATOR_AUTHOR_SITE}" in
|
||||
x) CFG_WITH_LONGTESTS=no ;;
|
||||
*) CFG_WITH_LONGTESTS=yes ;;
|
||||
esac]
|
||||
)
|
||||
AC_SUBST(CFG_WITH_LONGTESTS)
|
||||
AC_MSG_RESULT($CFG_WITH_LONGTESTS)
|
||||
|
||||
# Compiler flags
|
||||
CFLAGS=-I${includedir}
|
||||
CPPFLAGS=-I${includedir}
|
||||
CXXFLAGS=-I${includedir}
|
||||
LDFLAGS=-L${libdir}
|
||||
|
||||
dnl Checks for programs.
|
||||
# Checks for programs.
|
||||
AC_PROG_CC
|
||||
AC_PROG_CXX
|
||||
AC_PROG_INSTALL
|
||||
|
||||
AC_LANG_PUSH(C++)
|
||||
AC_MSG_CHECKING([that C++ compiler can compile simple program])
|
||||
AC_TRY_RUN([int main() { return 0; }],
|
||||
AC_RUN_IFELSE(
|
||||
[AC_LANG_SOURCE([int main() { return 0; }])],
|
||||
AC_MSG_RESULT(yes),
|
||||
AC_MSG_RESULT(no);AC_MSG_ERROR([a working C++ compiler is required]))
|
||||
AC_MSG_RESULT(no);AC_MSG_ERROR([a working C++ compiler is required]),
|
||||
AC_MSG_RESULT(yes))
|
||||
|
||||
AC_PATH_PROG(PERL,perl)
|
||||
if test "x$PERL" = "x" ; then
|
||||
@@ -45,33 +97,101 @@ if test "x$YACC" = "x" ; then
|
||||
AC_MSG_ERROR([Cannot find "bison" in your PATH, please install it])
|
||||
fi
|
||||
|
||||
dnl Checks for libraries.
|
||||
# Checks for libraries.
|
||||
|
||||
dnl Checks for header files.
|
||||
AC_HEADER_STDC
|
||||
AC_HEADER_SYS_WAIT
|
||||
AC_CHECK_HEADERS(fcntl.h unistd.h inttypes.h sys/file.h sys/time.h sys/un.h math.h stdint.h mingw/stdint.h)
|
||||
|
||||
dnl Checks for typedefs, structures
|
||||
# Checks for typedefs, structures
|
||||
AC_CHECK_TYPE(size_t,unsigned int)
|
||||
AC_CHECK_TYPE(uint_t,unsigned int)
|
||||
AC_CHECK_TYPE(ulong_t,unsigned long)
|
||||
AC_TYPE_SIZE_T
|
||||
AC_STRUCT_TM
|
||||
|
||||
dnl Checks for compiler characteristics.
|
||||
# Checks for compiler characteristics.
|
||||
AC_C_INLINE
|
||||
|
||||
dnl Checks for library functions.
|
||||
AC_DEFUN([_MY_CXX_CHECK_OPT],
|
||||
[# _MY_CXX_CHECK_OPT(flag) -- Check if compiler supports specific options
|
||||
ACO_SAVE_CXXFLAGS="$CXXFLAGS"
|
||||
# -Werror needed otherwise unknown -Wno-div-by-zero won't report problems
|
||||
CXXFLAGS="$CXXFLAGS $2 -Werror"
|
||||
AC_MSG_CHECKING([whether $CXX accepts $2])
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([],[])],
|
||||
[_my_result=yes
|
||||
if test -s conftest.err; then
|
||||
if grep -e "$2" conftest.err >/dev/null; then
|
||||
_my_result=no
|
||||
fi
|
||||
fi],
|
||||
[_my_result=no])
|
||||
# GCC is annoying, trying to be helpful, it postpones unknown -Wno-
|
||||
# options if there's no error We want to see them regardless, so try
|
||||
# forcing an error and see if we get a gcc warning
|
||||
AC_COMPILE_IFELSE(
|
||||
[AC_LANG_PROGRAM([[an_error "intentional-error-for-test.h"
|
||||
]],[])],
|
||||
[], # Ignore ok exit
|
||||
[if test -s conftest.err; then
|
||||
if grep -e "$2" conftest.err >/dev/null; then
|
||||
_my_result=no
|
||||
fi
|
||||
fi])
|
||||
AC_MSG_RESULT($_my_result)
|
||||
if test "$_my_result" = "yes" ; then
|
||||
$1="$$1 $2"
|
||||
fi
|
||||
CXXFLAGS="$ACO_SAVE_CXXFLAGS"
|
||||
])# _MY_CXX_CHECK_OPT
|
||||
|
||||
dnl Checks for system services
|
||||
# Flags for compiling Verilator internals including parser, and Verilated files
|
||||
# These turn on extra warnings and are only used with 'configure --enable-ccwarn'
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wextra)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_WEXTRA,-Wlogical-op)
|
||||
AC_SUBST(CFG_CXXFLAGS_WEXTRA)
|
||||
|
||||
dnl Other install directories
|
||||
# Flags for compiling Verilator internals including parser always
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Qunused-arguments)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-faligned-new)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-delete-null-pointer-checks)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-unused-parameter)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-undefined-bool-conversion)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-Wno-shadow)
|
||||
AC_SUBST(CFG_CXXFLAGS_SRC)
|
||||
|
||||
# Flags for compiling Verilator parser always (in addition to above CFG_CXXFLAGS_SRC)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-char-subscripts)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-null-conversion)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-parentheses-equality)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_PARSER,-Wno-unused)
|
||||
AC_SUBST(CFG_CXXFLAGS_PARSER)
|
||||
|
||||
# Flags for Verilated makefile
|
||||
# For example, -Wno-div-by-zero isn't in 4.1.2
|
||||
# Random code often does / 0. Unfortunately VL_DIV_I(0,0) will warn
|
||||
# without this flag, even though there's a conditional to prevent the divide.
|
||||
# We still don't add no-div-by-zero as it throws message to stdout, though doesn't die.
|
||||
#_MY_CXX_CHECK_OPT(-Wno-div-by-zero)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-faligned-new)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-fbracket-depth=4096)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Qunused-arguments)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-parentheses-equality)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-sign-compare)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-uninitialized)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-but-set-variable)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-parameter)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-unused-variable)
|
||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_NO_UNUSED,-Wno-shadow)
|
||||
AC_SUBST(CFG_CXXFLAGS_NO_UNUSED)
|
||||
|
||||
# Checks for library functions.
|
||||
|
||||
# Checks for system services
|
||||
|
||||
# Other install directories
|
||||
pkgdatadir=${datadir}/verilator
|
||||
AC_SUBST(pkgdatadir)
|
||||
pkgconfigdir=${datadir}/pkgconfig
|
||||
AC_SUBST(pkgconfigdir)
|
||||
|
||||
AC_OUTPUT(Makefile src/Makefile src/Makefile_obj include/verilated.mk)
|
||||
AC_OUTPUT
|
||||
|
||||
AC_MSG_RESULT([])
|
||||
AC_MSG_RESULT([Now type 'gmake'])
|
||||
AC_MSG_RESULT([Now type 'make' (or sometimes 'gmake') to build Verilator.])
|
||||
AC_MSG_RESULT([])
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
/*! \mainpage Verilator Doxygen Documentation
|
||||
*
|
||||
* \section intro_sec Introduction
|
||||
*
|
||||
* This is a full doxygen analysis of the Verilator source tree.
|
||||
*/
|
||||
+1770
File diff suppressed because it is too large
Load Diff
@@ -1 +1,2 @@
|
||||
verilated.mk
|
||||
verilated_config.h
|
||||
|
||||
+945
-219
File diff suppressed because it is too large
Load Diff
+781
-213
File diff suppressed because it is too large
Load Diff
+61
-59
@@ -2,7 +2,7 @@
|
||||
######################################################################
|
||||
# DESCRIPTION: Makefile commands for all verilated target files
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
# Copyright 2003-2017 by Wilson Snyder. Verilator is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
# General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
######################################################################
|
||||
@@ -13,11 +13,27 @@ LINK = @CXX@
|
||||
AR = ar
|
||||
RANLIB = ranlib
|
||||
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_LONGTESTS = @CFG_WITH_LONGTESTS@
|
||||
|
||||
# Compiler flags to use to turn off unused and generated code warnings, such as -Wno-div-by-zero
|
||||
CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
|
||||
# Compiler flags that turn on extra warnings
|
||||
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
|
||||
|
||||
######################################################################
|
||||
# Programs
|
||||
|
||||
SP_PREPROC = sp_preproc
|
||||
SP_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
|
||||
SP_INCLUDER = $(VERILATOR_INCLUDER)
|
||||
VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage
|
||||
VERILATOR_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
|
||||
|
||||
######################################################################
|
||||
# Make checks
|
||||
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
######################################################################
|
||||
# C Preprocessor flags
|
||||
@@ -26,24 +42,22 @@ SP_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
|
||||
VK_CPPFLAGS_ALWAYS += \
|
||||
-MMD \
|
||||
-I$(VERILATOR_ROOT)/include \
|
||||
-I$(VERILATOR_ROOT)/include/vltstd \
|
||||
-DVL_PRINTF=printf \
|
||||
-DVM_TRACE=$(VM_TRACE) \
|
||||
-DVM_COVERAGE=$(VM_COVERAGE) \
|
||||
-DVM_SC=$(VM_SC) \
|
||||
-DVM_TRACE=$(VM_TRACE) \
|
||||
$(CFG_CXXFLAGS_NO_UNUSED) \
|
||||
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
VK_CPPFLAGS_WALL += -Wall \
|
||||
-Wno-char-subscripts \
|
||||
-Wno-sign-compare \
|
||||
-Wno-unused-parameter \
|
||||
-Wno-unused-variable \
|
||||
-Wno-uninitialized \
|
||||
-Werror
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
VK_CPPFLAGS_WALL += -Wall $(CFG_CXXFLAGS_WEXTRA) -Werror
|
||||
endif
|
||||
|
||||
CPPFLAGS += -I. $(VK_CPPFLAGS_ALWAYS) $(VK_CPPFLAGS_WALL)
|
||||
CPPFLAGS += -I. $(VK_CPPFLAGS_WALL) $(VK_CPPFLAGS_ALWAYS)
|
||||
|
||||
VPATH += ..
|
||||
VPATH += $(VERILATOR_ROOT)/include
|
||||
VPATH += $(VERILATOR_ROOT)/include/vltstd
|
||||
|
||||
#OPT = -ggdb -DPRINTINITSTR -DDETECTCHANGE
|
||||
#OPT = -ggdb -DPRINTINITSTR
|
||||
@@ -56,6 +70,12 @@ LDFLAGS += $(M32)
|
||||
# These aren't ever set by Verilator, so users are free to override them.
|
||||
CPPFLAGS += $(USER_CPPFLAGS)
|
||||
LDFLAGS += $(USER_LDFLAGS)
|
||||
LDLIBS += $(USER_LDLIBS)
|
||||
|
||||
# Add flags from -CFLAGS and -LDFLAGS on Verilator command line
|
||||
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.
|
||||
@@ -73,58 +93,27 @@ VM_CLASSES += $(VM_CLASSES_FAST) $(VM_CLASSES_SLOW)
|
||||
VM_SUPPORT += $(VM_SUPPORT_FAST) $(VM_SUPPORT_SLOW)
|
||||
|
||||
#######################################################################
|
||||
##### SystemC or SystemPerl builds
|
||||
##### SystemC builds
|
||||
|
||||
ifeq ($(VM_SP_OR_SC),1)
|
||||
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC)/include
|
||||
LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC)/lib-$(VM_SC_TARGET_ARCH)
|
||||
ifeq ($(VM_SC),1)
|
||||
CPPFLAGS += $(SYSTEMC_CXX_FLAGS) -I$(SYSTEMC_INCLUDE)
|
||||
LDFLAGS += $(SYSTEMC_CXX_FLAGS) -L$(SYSTEMC_LIBDIR)
|
||||
SC_LIBS = -lsystemc
|
||||
ifneq ($(wildcard $(SYSTEMC)/lib-$(VM_SC_TARGET_ARCH)/*numeric_bit*),)
|
||||
ifneq ($(wildcard $(SYSTEMC_LIBDIR)/*numeric_bit*),)
|
||||
# Systemc 1.2.1beta
|
||||
SC_LIBS += -lnumeric_bit -lqt
|
||||
endif
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
##### SystemPerl builds
|
||||
##### Stub
|
||||
|
||||
ifeq ($(VM_SP),1)
|
||||
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE) -DSYSTEMPERL
|
||||
VPATH += $(SYSTEMPERL_INCLUDE)
|
||||
LIBS += -lm -lstdc++
|
||||
|
||||
VK_CLASSES_SP = $(addsuffix .sp, $(VM_CLASSES))
|
||||
|
||||
# This rule is called manually by the upper level makefile
|
||||
preproc:
|
||||
@echo " SP Preprocess" $(basename $(VM_CLASSES)) ...
|
||||
$(SP_PREPROC) -M sp_preproc.d --tree $(VM_PREFIX).sp_tree \
|
||||
--preproc $(VK_CLASSES_SP)
|
||||
else
|
||||
preproc:
|
||||
endif
|
||||
|
||||
#######################################################################
|
||||
##### SystemC w/o SystemPerl builds
|
||||
|
||||
ifeq ($(VM_SC),1)
|
||||
LIBS += -lm -lstdc++
|
||||
ifeq ($(VM_TRACE),1)
|
||||
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE)
|
||||
VPATH += $(SYSTEMPERL_INCLUDE)
|
||||
endif
|
||||
endif
|
||||
preproc:
|
||||
|
||||
#######################################################################
|
||||
##### C/H builds
|
||||
|
||||
ifeq ($(VM_PCLI),1)
|
||||
LIBS += -lm -lstdc++
|
||||
ifeq ($(VM_TRACE),1)
|
||||
CPPFLAGS += -I$(SYSTEMPERL_INCLUDE)
|
||||
VPATH += $(SYSTEMPERL_INCLUDE)
|
||||
endif
|
||||
endif
|
||||
LIBS += -lm -lstdc++
|
||||
|
||||
#######################################################################
|
||||
# Overall Objects Linking
|
||||
@@ -136,15 +125,17 @@ VK_SUPPORT_CPP = $(addsuffix .cpp, $(VM_SUPPORT))
|
||||
|
||||
VK_USER_OBJS = $(addsuffix .o, $(VM_USER_CLASSES))
|
||||
|
||||
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)
|
||||
$(SP_INCLUDER) $^ > $@
|
||||
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
|
||||
$(VM_PREFIX)__ALLsup.cpp: $(VK_SUPPORT_CPP)
|
||||
$(SP_INCLUDER) $^ > $@
|
||||
$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
|
||||
else
|
||||
#Slow way of building... Each .cpp file by itself
|
||||
VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT))
|
||||
@@ -158,26 +149,37 @@ $(VM_PREFIX)__ALL.a: $(VK_OBJS)
|
||||
######################################################################
|
||||
### Compile rules
|
||||
|
||||
#Default rule embedded in make: (Not defined so user makefiles can override it)
|
||||
#.cpp.o:
|
||||
# $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
ifneq ($(VM_DEFAULT_RULES),0)
|
||||
$(VM_PREFIX)__ALLsup.o: $(VM_PREFIX)__ALLsup.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
|
||||
|
||||
$(VM_PREFIX)__ALLcls.o: $(VM_PREFIX)__ALLcls.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
||||
|
||||
$(VM_PREFIX)%__Slow.o: $(VM_PREFIX)%__Slow.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
|
||||
|
||||
$(VM_PREFIX)%.o: $(VM_PREFIX)%.cpp
|
||||
$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
|
||||
endif
|
||||
|
||||
#Default rule embedded in make:
|
||||
#.cpp.o:
|
||||
# $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
######################################################################
|
||||
### Debugging
|
||||
|
||||
debug::
|
||||
debug-make::
|
||||
@echo
|
||||
@echo VM_PREFIX: $(VM_PREFIX)
|
||||
@echo VM_CLASSES_FAST: $(VM_CLASSES_FAST)
|
||||
@echo VM_CLASSES_SLOW: $(VM_CLASSES_SLOW)
|
||||
@echo VM_SUPPORT_FAST: $(VM_SUPPORT_FAST)
|
||||
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
|
||||
@echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST)
|
||||
@echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW)
|
||||
@echo CPPFLAGS: $(CPPFLAGS)
|
||||
@echo
|
||||
|
||||
######################################################################
|
||||
|
||||
+4
-9
@@ -1,11 +1,10 @@
|
||||
// -*- C++ -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -23,15 +22,11 @@
|
||||
`define _VERILATED_V_ 1
|
||||
|
||||
// Hide verilator pragmas from other tools
|
||||
`ifdef verilator `else
|
||||
`ifdef VERILATOR `else
|
||||
`define coverage_block_off
|
||||
`endif
|
||||
|
||||
// Hide file descriptor difference
|
||||
`ifdef verilator
|
||||
`define verilator_file_descriptor reg [63:0]
|
||||
`else
|
||||
`define verilator_file_descriptor integer
|
||||
`endif
|
||||
// Hide file descriptor difference - deprecated - for older versions
|
||||
`define verilator_file_descriptor integer
|
||||
|
||||
`endif // guard
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Auto version information include for all Verilated C files
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
///**** Product and Version name
|
||||
|
||||
// Autoconf substitutes this with the strings from AC_INIT.
|
||||
#define VERILATOR_PRODUCT "@PACKAGE_NAME@"
|
||||
#define VERILATOR_VERSION "@PACKAGE_VERSION@"
|
||||
@@ -0,0 +1,456 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator coverage analysis
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_cov.h"
|
||||
#include "verilated_cov_key.h"
|
||||
|
||||
#include <map>
|
||||
#include <deque>
|
||||
#include <fstream>
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCovImpBase
|
||||
/// Implementation base class for constants
|
||||
|
||||
struct VerilatedCovImpBase {
|
||||
// TYPES
|
||||
enum { MAX_KEYS = 33 }; /// Maximum user arguments + filename+lineno
|
||||
enum { KEY_UNDEF = 0 }; /// Magic key # for unspecified values
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCovImpItem
|
||||
/// Implementation class for a VerilatedCov item
|
||||
|
||||
class VerilatedCovImpItem : VerilatedCovImpBase {
|
||||
public: // But only local to this file
|
||||
// MEMBERS
|
||||
int m_keys[MAX_KEYS]; ///< Key
|
||||
int m_vals[MAX_KEYS]; ///< Value for specified key
|
||||
// CONSTRUCTORS
|
||||
// Derived classes should call zero() in their constructor
|
||||
VerilatedCovImpItem() {
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
m_keys[i]=KEY_UNDEF;
|
||||
m_vals[i]=0;
|
||||
}
|
||||
}
|
||||
virtual ~VerilatedCovImpItem() {}
|
||||
virtual vluint64_t count() const = 0;
|
||||
virtual void zero() const = 0;
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
/// VerilatedCoverItem templated for a specific class
|
||||
/// Creates a new coverage item for the specified type.
|
||||
/// This isn't in the header file for auto-magic conversion because it
|
||||
/// inlines to too much code and makes compilation too slow.
|
||||
|
||||
template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
|
||||
private:
|
||||
// MEMBERS
|
||||
T* m_countp; ///< Count value
|
||||
public:
|
||||
// METHODS
|
||||
// cppcheck-suppress truncLongCastReturn
|
||||
virtual vluint64_t count() const { return *m_countp; }
|
||||
virtual void zero() const { *m_countp = 0; }
|
||||
// CONSTRUCTORS
|
||||
// cppcheck-suppress noExplicitConstructor
|
||||
VerilatedCoverItemSpec(T* countp) : m_countp(countp) { zero(); }
|
||||
virtual ~VerilatedCoverItemSpec() {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCovImp
|
||||
/// Implementation class for VerilatedCov. See that class for public method information.
|
||||
/// All value and keys are indexed into a unique number. Thus we can greatly reduce
|
||||
/// the storage requirements for otherwise identical keys.
|
||||
|
||||
class VerilatedCovImp : VerilatedCovImpBase {
|
||||
private:
|
||||
// TYPES
|
||||
typedef std::map<std::string,int> ValueIndexMap;
|
||||
typedef std::map<int,std::string> IndexValueMap;
|
||||
typedef std::deque<VerilatedCovImpItem*> ItemList;
|
||||
|
||||
private:
|
||||
// MEMBERS
|
||||
ValueIndexMap m_valueIndexes; ///< For each key/value a unique arbitrary index value
|
||||
IndexValueMap m_indexValues; ///< For each key/value a unique arbitrary index value
|
||||
ItemList m_items; ///< List of all items
|
||||
|
||||
VerilatedCovImpItem* m_insertp; ///< Item about to insert
|
||||
const char* m_insertFilenamep; ///< Filename about to insert
|
||||
int m_insertLineno; ///< Line number about to insert
|
||||
|
||||
// CONSTRUCTORS
|
||||
VerilatedCovImp() {
|
||||
m_insertp = NULL;
|
||||
m_insertFilenamep = NULL;
|
||||
m_insertLineno = 0;
|
||||
}
|
||||
public:
|
||||
~VerilatedCovImp() { clear(); }
|
||||
static VerilatedCovImp& imp() {
|
||||
static VerilatedCovImp s_singleton;
|
||||
return s_singleton;
|
||||
}
|
||||
|
||||
private:
|
||||
// PRIVATE METHODS
|
||||
int valueIndex(const std::string& value) {
|
||||
static int nextIndex = KEY_UNDEF+1;
|
||||
ValueIndexMap::iterator iter = m_valueIndexes.find(value);
|
||||
if (iter != m_valueIndexes.end()) return iter->second;
|
||||
nextIndex++; assert(nextIndex>0);
|
||||
m_valueIndexes.insert(std::make_pair(value, nextIndex));
|
||||
m_indexValues.insert(std::make_pair(nextIndex, value));
|
||||
return nextIndex;
|
||||
}
|
||||
std::string dequote(const std::string& text) {
|
||||
// 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]);
|
||||
rtn += hex;
|
||||
} else {
|
||||
rtn += *pos;
|
||||
}
|
||||
}
|
||||
return rtn;
|
||||
}
|
||||
bool legalKey(const std::string& key) {
|
||||
// Because we compress long keys to a single letter, and
|
||||
// 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;
|
||||
return true;
|
||||
}
|
||||
std::string keyValueFormatter (const std::string& key, const std::string& value) {
|
||||
std::string name;
|
||||
if (key.length()==1 && isalpha(key[0])) {
|
||||
name += std::string("\001")+key;
|
||||
} else {
|
||||
name += std::string("\001")+dequote(key);
|
||||
}
|
||||
name += std::string("\002")+dequote(value);
|
||||
return name;
|
||||
}
|
||||
std::string combineHier (const std::string& old, const std::string& add) {
|
||||
// (foo.a.x, foo.b.x) => foo.*.x
|
||||
// (foo.a.x, foo.b.y) => foo.*
|
||||
// (foo.a.x, foo.b) => foo.*
|
||||
if (old == add) return add;
|
||||
if (old == "") return add;
|
||||
if (add == "") return old;
|
||||
|
||||
const char* a = old.c_str();
|
||||
const char* b = add.c_str();
|
||||
|
||||
// Scan forward to first mismatch
|
||||
const char* apre = a;
|
||||
const char* bpre = b;
|
||||
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);
|
||||
|
||||
// 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--; }
|
||||
|
||||
// Forward to . so we have a whole word
|
||||
std::string suffix = *bpost ? std::string(bpost+1) : "";
|
||||
|
||||
std::string out = prefix+"*"+suffix;
|
||||
|
||||
//cout << "\nch pre="<<prefix<<" s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
|
||||
return out;
|
||||
}
|
||||
bool itemMatchesString(VerilatedCovImpItem* itemp, const std::string& match) {
|
||||
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]];
|
||||
if (std::string::npos != val.find(match)) { // Found
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
void selftest() {
|
||||
// Little selftest
|
||||
if (combineHier ("a.b.c","a.b.c") !="a.b.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.b.c","a.b") !="a.b*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.x.c","a.y.c") !="a.*.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("a.z.z.z.c","a.b.c") !="a.*.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("z","a") !="*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("q.a","q.b") !="q.*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("q.za","q.zb") !="q.z*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
if (combineHier ("1.2.3.a","9.8.7.a") !="*.a") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
|
||||
}
|
||||
|
||||
public:
|
||||
// PUBLIC METHODS
|
||||
void clear() {
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
delete itemp;
|
||||
}
|
||||
m_items.clear();
|
||||
m_indexValues.clear();
|
||||
m_valueIndexes.clear();
|
||||
}
|
||||
void clearNonMatch (const char* matchp) {
|
||||
if (matchp && matchp[0]) {
|
||||
ItemList newlist;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
if (!itemMatchesString(itemp, matchp)) {
|
||||
delete itemp;
|
||||
} else {
|
||||
newlist.push_back(itemp);
|
||||
}
|
||||
}
|
||||
m_items = newlist;
|
||||
}
|
||||
}
|
||||
void zero() {
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
(*it)->zero();
|
||||
}
|
||||
}
|
||||
|
||||
// We assume there's always call to i/f/p in that order
|
||||
void inserti (VerilatedCovImpItem* itemp) {
|
||||
assert(!m_insertp);
|
||||
m_insertp = itemp;
|
||||
}
|
||||
void insertf (const char* filenamep, int lineno) {
|
||||
m_insertFilenamep = filenamep;
|
||||
m_insertLineno = lineno;
|
||||
}
|
||||
void insertp (const char* ckeyps[MAX_KEYS],
|
||||
const char* valps[MAX_KEYS]) {
|
||||
assert(m_insertp);
|
||||
// First two key/vals are filename
|
||||
ckeyps[0]="filename"; valps[0]=m_insertFilenamep;
|
||||
std::string linestr = vlCovCvtToStr(m_insertLineno);
|
||||
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;
|
||||
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();
|
||||
|
||||
// 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];
|
||||
}
|
||||
}
|
||||
// Ignore empty keys
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
if (keys[i]!="") {
|
||||
for (int j=i+1; j<MAX_KEYS; ++j) {
|
||||
if (keys[i] == keys[j]) { // Duplicate key. Keep the last one
|
||||
keys[i] = "";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Insert the values
|
||||
int addKeynum=0;
|
||||
for (int i=0; i<MAX_KEYS; ++i) {
|
||||
const std::string key = keys[i];
|
||||
if (keys[i]!="") {
|
||||
const std::string val = valps[i];
|
||||
//cout<<" "<<__FUNCTION__<<" "<<key<<" = "<<val<<endl;
|
||||
m_insertp->m_keys[addKeynum] = valueIndex(key);
|
||||
m_insertp->m_vals[addKeynum] = valueIndex(val);
|
||||
addKeynum++;
|
||||
if (!legalKey(key)) {
|
||||
std::string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
m_items.push_back(m_insertp);
|
||||
// Prepare for next
|
||||
m_insertp = NULL;
|
||||
}
|
||||
|
||||
void write (const char* filename) {
|
||||
#ifndef VM_COVERAGE
|
||||
vl_fatal("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
|
||||
#endif
|
||||
selftest();
|
||||
|
||||
std::ofstream os (filename);
|
||||
if (os.fail()) {
|
||||
std::string msg = (std::string)"%Error: Can't write '"+filename+"'";
|
||||
vl_fatal("",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;
|
||||
EventMap eventCounts;
|
||||
for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
|
||||
VerilatedCovImpItem* itemp = *(it);
|
||||
std::string name;
|
||||
std::string hier;
|
||||
bool per_instance = false;
|
||||
|
||||
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]];
|
||||
if (key == VL_CIK_PER_INSTANCE) {
|
||||
if (val != "0") per_instance = true;
|
||||
}
|
||||
if (key == VL_CIK_HIER) {
|
||||
hier = val;
|
||||
} else {
|
||||
// Print it
|
||||
name += keyValueFormatter(key,val);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (per_instance) { // Not collapsing hierarchies
|
||||
name += keyValueFormatter(VL_CIK_HIER,hier);
|
||||
hier = "";
|
||||
}
|
||||
|
||||
// Group versus point labels don't matter here, downstream
|
||||
// deals with it. Seems bad for sizing though and doesn't
|
||||
// allow easy addition of new group codes (would be
|
||||
// inefficient)
|
||||
|
||||
// Find or insert the named event
|
||||
EventMap::iterator 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);
|
||||
} else {
|
||||
eventCounts.insert(std::make_pair(name, make_pair(hier,itemp->count())));
|
||||
}
|
||||
}
|
||||
|
||||
// Output body
|
||||
for (EventMap::iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
|
||||
os<<"C '"<<std::dec;
|
||||
os<<it->first;
|
||||
if (it->second.first != "") os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
|
||||
os<<"' "<<it->second.second;
|
||||
os<<std::endl;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCov
|
||||
|
||||
void VerilatedCov::clear() {
|
||||
VerilatedCovImp::imp().clear();
|
||||
}
|
||||
void VerilatedCov::clearNonMatch (const char* matchp) {
|
||||
VerilatedCovImp::imp().clearNonMatch(matchp);
|
||||
}
|
||||
void VerilatedCov::zero() {
|
||||
VerilatedCovImp::imp().zero();
|
||||
}
|
||||
void VerilatedCov::write (const char* filenamep) {
|
||||
VerilatedCovImp::imp().write(filenamep);
|
||||
}
|
||||
void VerilatedCov::_inserti (vluint32_t* itemp) {
|
||||
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint32_t>(itemp));
|
||||
}
|
||||
void VerilatedCov::_inserti (vluint64_t* itemp) {
|
||||
VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
|
||||
}
|
||||
void VerilatedCov::_insertf (const char* filename, int lineno) {
|
||||
VerilatedCovImp::imp().insertf(filename,lineno);
|
||||
}
|
||||
|
||||
#define K(n) const char* key ## n
|
||||
#define A(n) const char* key ## n, const char* val ## n // Argument list
|
||||
#define C(n) key ## n, val ## 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)) {
|
||||
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};
|
||||
const char* valps[VerilatedCovImpBase::MAX_KEYS]
|
||||
= {NULL,NULL,NULL, // filename,lineno,page
|
||||
val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,
|
||||
val10,val11,val12,val13,val14,val15,val16,val17,val18,val19,
|
||||
val20,val21,val22,val23,val24,val25,val26,val27,val28,val29};
|
||||
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)) {
|
||||
_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)) {
|
||||
_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)) {
|
||||
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));
|
||||
}
|
||||
#undef A
|
||||
#undef C
|
||||
#undef N
|
||||
#undef K
|
||||
@@ -0,0 +1,130 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Coverage analysis support
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#ifndef _VERILATED_COV_H_
|
||||
#define _VERILATED_COV_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
//=============================================================================
|
||||
/// Conditionally compile coverage code
|
||||
|
||||
#ifdef VM_COVERAGE
|
||||
# define VL_IF_COVER(stmts) do { stmts ; } while(0)
|
||||
#else
|
||||
# define VL_IF_COVER(stmts) do { if(0) { stmts ; } } while(0)
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
/// Insert a item for coverage analysis.
|
||||
/// The first argument is a pointer to the count to be dumped.
|
||||
/// The remaining arguments occur in pairs: A string key, and a value.
|
||||
/// The value may be a string, or another type which will be auto-converted to a string.
|
||||
///
|
||||
/// Some typical keys:
|
||||
/// filename File the recording occurs in. Defaults to __FILE__
|
||||
/// lineno Line number the recording occurs in. Defaults to __LINE__
|
||||
/// column Column number (or occurrence# for dup file/lines). Defaults to undef.
|
||||
/// hier Hierarchical name. Defaults to name()
|
||||
/// type Type of coverage. Defaults to "user"
|
||||
/// Other types are 'block', 'fsm', 'toggle'.
|
||||
/// comment Description of the coverage event. Should be set by the user.
|
||||
/// Comments for type==block: 'if', 'else', 'elsif', 'case'
|
||||
/// thresh Threshold to consider fully covered.
|
||||
/// If unspecified, downstream tools will determine it.
|
||||
///
|
||||
/// Examples:
|
||||
///
|
||||
/// vluint32_t m_cases[10];
|
||||
/// constructor {
|
||||
/// for (int i=0; i<10; ++i) { m_cases[i]=0; }
|
||||
/// }
|
||||
/// for (int i=0; i<10; ++i) {
|
||||
/// VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
|
||||
/// }
|
||||
|
||||
#define VL_COVER_INSERT(countp,args...) \
|
||||
VL_IF_COVER(VerilatedCov::_inserti(countp); \
|
||||
VerilatedCov::_insertf(__FILE__,__LINE__); \
|
||||
VerilatedCov::_insertp("hier", name(), args))
|
||||
|
||||
//=============================================================================
|
||||
/// Convert VL_COVER_INSERT value arguments to strings
|
||||
|
||||
template< class T> std::string vlCovCvtToStr (const T& t) {
|
||||
std::ostringstream os; os<<t; return os.str();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCov
|
||||
/// Verilator coverage global class
|
||||
////
|
||||
/// Global class with methods affecting all coverage data.
|
||||
|
||||
class VerilatedCov {
|
||||
public:
|
||||
// GLOBAL METHODS
|
||||
/// Return default filename
|
||||
static const char* defaultFilename() { return "coverage.dat"; }
|
||||
/// Write all coverage data to a file
|
||||
static void write (const char* filenamep = defaultFilename());
|
||||
/// Insert a coverage item
|
||||
/// We accept from 1-30 key/value pairs, all as strings.
|
||||
/// Call _insert1, followed by _insert2 and _insert3
|
||||
/// Do not call directly; use VL_COVER_INSERT or higher level macros instead
|
||||
// _insert1: Remember item pointer with count. (Not const, as may add zeroing function)
|
||||
static void _inserti (vluint32_t* itemp);
|
||||
static void _inserti (vluint64_t* itemp);
|
||||
// _insert2: Set default filename and line number
|
||||
static void _insertf (const char* filename, int lineno);
|
||||
// _insert3: Set parameters
|
||||
// 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));
|
||||
// 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));
|
||||
|
||||
#undef K
|
||||
#undef A
|
||||
#undef D
|
||||
/// Clear coverage points (and call delete on all items)
|
||||
static void clear();
|
||||
/// Clear items not matching the provided string
|
||||
static void clearNonMatch (const char* matchp);
|
||||
/// Zero coverage points
|
||||
static void zero();
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
@@ -0,0 +1,144 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Coverage item keys
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#ifndef _VERILATED_COV_KEY_H_
|
||||
#define _VERILATED_COV_KEY_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
//=============================================================================
|
||||
// Data used to edit below file, using vlcovgen
|
||||
|
||||
#define VLCOVGEN_ITEM(string_parsed_by_vlcovgen)
|
||||
|
||||
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, ")
|
||||
VLCOVGEN_ITEM("name=>'col3_name', short=>'C3', group=>1, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'column', short=>'n', group=>1, default=>0, descr=>'Column number for the item. Used to disambiguate multiple coverage points on the same line number'")
|
||||
VLCOVGEN_ITEM("name=>'filename', short=>'f', group=>1, default=>undef, descr=>'Filename of the item'")
|
||||
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=>'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, ")
|
||||
VLCOVGEN_ITEM("name=>'row2_name', short=>'R2', group=>1, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'row3_name', short=>'R3', group=>1, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'table', short=>'T', group=>1, default=>undef, descr=>'The name of the table for automatically generated tables'")
|
||||
VLCOVGEN_ITEM("name=>'thresh', short=>'s', group=>1, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'type', short=>'t', group=>1, default=>'', descr=>'Type of coverage (block, line, fsm, etc)'")
|
||||
// Bin attributes
|
||||
VLCOVGEN_ITEM("name=>'col0', short=>'c0', group=>0, default=>undef, descr=>'The (enumeration) value name for this column in a table cross' ")
|
||||
VLCOVGEN_ITEM("name=>'col1', short=>'c1', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'col2', short=>'c2', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'col3', short=>'c3', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'comment', short=>'o', group=>0, default=>'', descr=>'Textual description for the item'")
|
||||
VLCOVGEN_ITEM("name=>'hier', short=>'h', group=>0, default=>'', descr=>'Hierarchy path name for the item'")
|
||||
VLCOVGEN_ITEM("name=>'limit', short=>'L', group=>0, default=>undef, ")
|
||||
VLCOVGEN_ITEM("name=>'lineno', short=>'l', group=>0, default=>0, descr=>'Line number for the item'")
|
||||
VLCOVGEN_ITEM("name=>'row0', short=>'r0', group=>0, default=>undef, descr=>'The (enumeration) value name for this row in a table cross'")
|
||||
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'")
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedCovKey
|
||||
/// Verilator coverage global class
|
||||
////
|
||||
/// Global class with methods affecting all coverage data.
|
||||
|
||||
// VLCOVGEN_CIK_AUTO_EDIT_BEGIN
|
||||
#define VL_CIK_COL0 "c0"
|
||||
#define VL_CIK_COL0_NAME "C0"
|
||||
#define VL_CIK_COL1 "c1"
|
||||
#define VL_CIK_COL1_NAME "C1"
|
||||
#define VL_CIK_COL2 "c2"
|
||||
#define VL_CIK_COL2_NAME "C2"
|
||||
#define VL_CIK_COL3 "c3"
|
||||
#define VL_CIK_COL3_NAME "C3"
|
||||
#define VL_CIK_COLUMN "n"
|
||||
#define VL_CIK_COMMENT "o"
|
||||
#define VL_CIK_FILENAME "f"
|
||||
#define VL_CIK_GROUPCMT "O"
|
||||
#define VL_CIK_GROUPDESC "d"
|
||||
#define VL_CIK_GROUPNAME "g"
|
||||
#define VL_CIK_HIER "h"
|
||||
#define VL_CIK_LIMIT "L"
|
||||
#define VL_CIK_LINENO "l"
|
||||
#define VL_CIK_PER_INSTANCE "P"
|
||||
#define VL_CIK_ROW0 "r0"
|
||||
#define VL_CIK_ROW0_NAME "R0"
|
||||
#define VL_CIK_ROW1 "r1"
|
||||
#define VL_CIK_ROW1_NAME "R1"
|
||||
#define VL_CIK_ROW2 "r2"
|
||||
#define VL_CIK_ROW2_NAME "R2"
|
||||
#define VL_CIK_ROW3 "r3"
|
||||
#define VL_CIK_ROW3_NAME "R3"
|
||||
#define VL_CIK_TABLE "T"
|
||||
#define VL_CIK_THRESH "s"
|
||||
#define VL_CIK_TYPE "t"
|
||||
#define VL_CIK_WEIGHT "w"
|
||||
// VLCOVGEN_CIK_AUTO_EDIT_END
|
||||
|
||||
class VerilatedCovKey {
|
||||
public:
|
||||
static std::string shortKey(const std::string& key) {
|
||||
// VLCOVGEN_SHORT_AUTO_EDIT_BEGIN
|
||||
if (key == "col0") return VL_CIK_COL0;
|
||||
if (key == "col0_name") return VL_CIK_COL0_NAME;
|
||||
if (key == "col1") return VL_CIK_COL1;
|
||||
if (key == "col1_name") return VL_CIK_COL1_NAME;
|
||||
if (key == "col2") return VL_CIK_COL2;
|
||||
if (key == "col2_name") return VL_CIK_COL2_NAME;
|
||||
if (key == "col3") return VL_CIK_COL3;
|
||||
if (key == "col3_name") return VL_CIK_COL3_NAME;
|
||||
if (key == "column") return VL_CIK_COLUMN;
|
||||
if (key == "comment") return VL_CIK_COMMENT;
|
||||
if (key == "filename") return VL_CIK_FILENAME;
|
||||
if (key == "groupcmt") return VL_CIK_GROUPCMT;
|
||||
if (key == "groupdesc") return VL_CIK_GROUPDESC;
|
||||
if (key == "groupname") return VL_CIK_GROUPNAME;
|
||||
if (key == "hier") return VL_CIK_HIER;
|
||||
if (key == "limit") return VL_CIK_LIMIT;
|
||||
if (key == "lineno") return VL_CIK_LINENO;
|
||||
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;
|
||||
if (key == "row1") return VL_CIK_ROW1;
|
||||
if (key == "row1_name") return VL_CIK_ROW1_NAME;
|
||||
if (key == "row2") return VL_CIK_ROW2;
|
||||
if (key == "row2_name") return VL_CIK_ROW2_NAME;
|
||||
if (key == "row3") return VL_CIK_ROW3;
|
||||
if (key == "row3_name") return VL_CIK_ROW3_NAME;
|
||||
if (key == "table") return VL_CIK_TABLE;
|
||||
if (key == "thresh") return VL_CIK_THRESH;
|
||||
if (key == "type") return VL_CIK_TYPE;
|
||||
if (key == "weight") return VL_CIK_WEIGHT;
|
||||
// VLCOVGEN_SHORT_AUTO_EDIT_END
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
@@ -0,0 +1,303 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: DPI implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all objects
|
||||
/// created from Verilator or called by Verilator that use the DPI.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#define _VERILATED_DPI_CPP_
|
||||
#include "verilatedos.h"
|
||||
#include "verilated_dpi.h"
|
||||
#include "verilated_imp.h"
|
||||
|
||||
// On MSVC++ we need svdpi.h to declare exports, not imports
|
||||
#define DPI_PROTOTYPES
|
||||
#define XXTERN DPI_EXTERN DPI_DLLESPEC
|
||||
#define EETERN DPI_EXTERN DPI_DLLESPEC
|
||||
|
||||
#include "vltstd/svdpi.h"
|
||||
|
||||
//======================================================================
|
||||
// Internal macros
|
||||
|
||||
// Not supported yet
|
||||
#define _VL_SVDPI_UNIMP() \
|
||||
vl_fatal(__FILE__,__LINE__,"",(std::string("%%Error: Unsupported DPI function: ")+VL_FUNC).c_str())
|
||||
|
||||
// Function requires a "context" in the import declaration
|
||||
#define _VL_SVDPI_CONTEXT_WARN() \
|
||||
VL_PRINTF("%%Warning: DPI C Function called by Verilog DPI import with missing 'context' keyword.\n");
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
// DPI ROUTINES
|
||||
|
||||
const char* svDpiVersion() {
|
||||
return "1800-2005";
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Bit-select utility functions.
|
||||
|
||||
svBit svGetBitselBit(const svBitVecVal* sp, int bit) {
|
||||
return VL_BITISSET_W(sp,bit);
|
||||
}
|
||||
svLogic svGetBitselLogic(const svLogicVecVal* sp, int bit) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void svPutBitselBit(svBitVecVal* dp, int bit, svBit s) {
|
||||
VL_ASSIGNBIT_WI(32, bit, dp, s);
|
||||
}
|
||||
void svPutBitselLogic(svLogicVecVal* dp, int bit, svLogic s) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
void svGetPartselBit(svBitVecVal* dp, const svBitVecVal* sp, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
void svPutPartselBit(svBitVecVal* dp, const svBitVecVal s, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal* sp, int i, int w) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Open array querying functions
|
||||
|
||||
int svLeft(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svRight(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svLow(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svHigh(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svIncrement(const svOpenArrayHandle h, int d) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
int svDimensions(const svOpenArrayHandle h) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void *svGetArrayPtr(const svOpenArrayHandle) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
int svSizeOfArray(const svOpenArrayHandle) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
|
||||
void *svGetArrElemPtr(const svOpenArrayHandle, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr1(const svOpenArrayHandle, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr2(const svOpenArrayHandle, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
void *svGetArrElemPtr3(const svOpenArrayHandle, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return NULL;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// s=source, d=destination
|
||||
// From user space into simulator storage
|
||||
|
||||
void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// From simulator storage into user space
|
||||
|
||||
void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return 0;
|
||||
}
|
||||
svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP(); return sv_x;
|
||||
}
|
||||
void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1, int indx2) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1, int indx2, int indx3) {
|
||||
_VL_SVDPI_UNIMP();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Functions for working with DPI context
|
||||
|
||||
svScope svGetScope() {
|
||||
if (VL_UNLIKELY(!Verilated::dpiInContext())) { _VL_SVDPI_CONTEXT_WARN(); return NULL; }
|
||||
return (svScope)Verilated::dpiScope();
|
||||
}
|
||||
|
||||
svScope svSetScope(const svScope scope) {
|
||||
const VerilatedScope* prevScopep = Verilated::dpiScope();
|
||||
const VerilatedScope* vscopep = (const VerilatedScope*)(scope);
|
||||
Verilated::dpiScope(vscopep);
|
||||
return (svScope)prevScopep;
|
||||
}
|
||||
|
||||
const char* svGetNameFromScope(const svScope scope) {
|
||||
const VerilatedScope* vscopep = (const VerilatedScope*)(scope);
|
||||
return vscopep->name();
|
||||
}
|
||||
|
||||
svScope svGetScopeFromName(const char* scopeName) {
|
||||
return (svScope)VerilatedImp::scopeFind(scopeName);
|
||||
}
|
||||
|
||||
int svPutUserData(const svScope scope, void *userKey, void* userData) {
|
||||
VerilatedImp::userInsert(scope,userKey,userData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* svGetUserData(const svScope scope, void* userKey) {
|
||||
return VerilatedImp::userFind(scope,userKey);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Disables
|
||||
|
||||
int svIsDisabledState() {
|
||||
return 0; // Disables not implemented
|
||||
}
|
||||
|
||||
void svAckDisabledState() {
|
||||
// Disables not implemented
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Common include for all Verilated C files that use DPI
|
||||
///
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all C++ files it generates where DPI is used. It contains
|
||||
/// DPI interface functions required by the Verilated code.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATED_DPI_H_
|
||||
#define _VERILATED_DPI_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilated.h" // Presumed done by caller
|
||||
#include "svdpi.h"
|
||||
|
||||
//===================================================================
|
||||
// SETTING OPERATORS
|
||||
|
||||
/// Return svBitVecVal from WData
|
||||
static inline void VL_SET_W_SVBV(int obits, WDataOutP owp, svBitVecVal* lwp) {
|
||||
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);
|
||||
}
|
||||
static inline void VL_SET_SVBV_W(int obits, svBitVecVal* owp, WDataInP lwp) {
|
||||
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);
|
||||
}
|
||||
static inline void VL_SET_W_SVLV(int obits, WDataOutP owp, svLogicVecVal* lwp) {
|
||||
// Note we ignore X/Z in svLogicVecVal
|
||||
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);
|
||||
}
|
||||
static inline void VL_SET_SVLV_W(int obits, svLogicVecVal* owp, WDataInP lwp) {
|
||||
// Note we don't create X/Z in svLogicVecVal
|
||||
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);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
#endif // _VERILATED_DPI_H_
|
||||
@@ -0,0 +1,84 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2010-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: String include for all Verilated C files
|
||||
///
|
||||
/// This file is included automatically by Verilator at the top of
|
||||
/// all C++ files it generates. It is used when strings or other
|
||||
/// heavyweight types are required; these contents are not part of
|
||||
/// verilated.h to save compile time when such types aren't used.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATED_HEAVY_H_
|
||||
#define _VERILATED_HEAVY_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilated.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
//======================================================================
|
||||
// Conversion functions
|
||||
|
||||
extern std::string VL_CVT_PACK_STR_NW(int lwords, WDataInP lwp);
|
||||
inline std::string VL_CVT_PACK_STR_NQ(QData lhs) {
|
||||
WData lw[2]; VL_SET_WQ(lw, lhs);
|
||||
return VL_CVT_PACK_STR_NW(2, lw);
|
||||
}
|
||||
inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) {
|
||||
return lhs;
|
||||
}
|
||||
inline std::string VL_CVT_PACK_STR_NI(IData lhs) {
|
||||
WData lw[1]; lw[0] = lhs;
|
||||
return VL_CVT_PACK_STR_NW(1, lw);
|
||||
}
|
||||
inline std::string VL_CONCATN_NNN(const std::string& lhs, const std::string& rhs) {
|
||||
return lhs+rhs;
|
||||
}
|
||||
inline std::string VL_REPLICATEN_NNQ(int,int,int, const std::string& lhs, IData rep) {
|
||||
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) {
|
||||
return VL_REPLICATEN_NNQ(obits,lbits,rbits,lhs,rep);
|
||||
}
|
||||
|
||||
extern IData VL_FOPEN_NI(const std::string& filename, IData mode);
|
||||
extern void VL_READMEM_N(bool hex, int width, int depth, int array_lsb, int fnwords,
|
||||
const std::string& ofilename, void* memp, IData start, IData end);
|
||||
extern IData VL_SSCANF_INX(int lbits, const std::string& ld, const char* formatp, ...);
|
||||
extern void VL_SFORMAT_X(int obits_ignored, std::string &output, const char* formatp, ...);
|
||||
extern std::string VL_SFORMATF_NX(const char* formatp, ...);
|
||||
extern IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rdp);
|
||||
inline IData VL_VALUEPLUSARGS_INI(int rbits, const std::string& ld, IData& rdr) {
|
||||
WData rwp[2]; // WData must always be at least 2
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
|
||||
if (got) rdr = rwp[0];
|
||||
return got;
|
||||
}
|
||||
inline IData VL_VALUEPLUSARGS_INQ(int rbits, const std::string& ld, QData& rdr) {
|
||||
WData rwp[2];
|
||||
IData got = VL_VALUEPLUSARGS_INW(rbits,ld,rwp);
|
||||
if (got) rdr = VL_SET_QW(rwp);
|
||||
return got;
|
||||
}
|
||||
extern IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr);
|
||||
|
||||
#endif // Guard
|
||||
@@ -0,0 +1,261 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Implementation Header, only for verilated.cpp internals.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
|
||||
#ifndef _VERILATED_IMP_H_
|
||||
#define _VERILATED_IMP_H_ 1 ///< Header Guard
|
||||
|
||||
#if !defined(_VERILATED_CPP_) && !defined(_VERILATED_DPI_CPP_)
|
||||
# error "verilated_imp.h only to be included by verilated*.cpp internals"
|
||||
#endif
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_heavy.h"
|
||||
#include "verilated_syms.h"
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
class VerilatedScope;
|
||||
|
||||
//======================================================================
|
||||
// Types
|
||||
|
||||
class VerilatedImp {
|
||||
// Whole class is internal use only - Global information shared between verilated*.cpp files.
|
||||
|
||||
// TYPES
|
||||
typedef std::vector<std::string> ArgVec;
|
||||
typedef std::map<std::pair<const void*,void*>,void*> UserMap;
|
||||
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
|
||||
|
||||
ArgVec m_argVec; ///< Argument list (NOT save-restored, may want different results)
|
||||
bool m_argVecLoaded; ///< Ever loaded argument list
|
||||
UserMap m_userMap; ///< Map of <(scope,userkey), userData>
|
||||
VerilatedScopeNameMap m_nameMap; ///< Map of <scope_name, scope pointer>
|
||||
// Slow - somewhat static:
|
||||
ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number>
|
||||
int m_exportNext; ///< Next export funcnum
|
||||
|
||||
// File I/O
|
||||
std::vector<FILE*> m_fdps; ///< File descriptors
|
||||
std::deque<IData> m_fdFree; ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
|
||||
|
||||
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() {}
|
||||
static void internalsDump() {
|
||||
VL_PRINTF("internalsDump:\n");
|
||||
VL_PRINTF(" Argv:");
|
||||
for (ArgVec::iterator it=s_s.m_argVec.begin(); it!=s_s.m_argVec.end(); ++it) {
|
||||
VL_PRINTF(" %s",it->c_str());
|
||||
}
|
||||
VL_PRINTF("\n");
|
||||
VL_PRINTF(" Version: %s %s\n", Verilated::productName(), Verilated::productVersion());
|
||||
scopesDump();
|
||||
exportsDump();
|
||||
userDump();
|
||||
}
|
||||
|
||||
// METHODS - arguments
|
||||
static void commandArgs(int argc, const char** argv) {
|
||||
s_s.m_argVec.clear(); // Always clear
|
||||
commandArgsAdd(argc, argv);
|
||||
}
|
||||
static void commandArgsAdd(int argc, const char** argv) {
|
||||
if (!s_s.m_argVecLoaded) s_s.m_argVec.clear();
|
||||
for (int i=0; i<argc; ++i) s_s.m_argVec.push_back(argv[i]);
|
||||
s_s.m_argVecLoaded = true; // Can't just test later for empty vector, no arguments is ok
|
||||
}
|
||||
static std::string argPlusMatch(const char* prefixp) {
|
||||
// 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
|
||||
vl_fatal("unknown",0,"",
|
||||
"%Error: Verilog called $test$plusargs or $value$plusargs without"
|
||||
" testbench C first calling Verilated::commandArgs(argc,argv).");
|
||||
}
|
||||
for (ArgVec::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;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
// METHODS - user scope tracking
|
||||
// We implement this as a single large map instead of one map per scope
|
||||
// There's often many more scopes than userdata's and thus having a ~48byte
|
||||
// per map overhead * N scopes would take much more space and cache thrashing.
|
||||
static inline void userInsert(const void* scopep, void* userKey, void* userData) {
|
||||
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));
|
||||
}
|
||||
static inline void* userFind(const void* scopep, void* userKey) {
|
||||
UserMap::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;
|
||||
}
|
||||
private:
|
||||
/// Symbol table destruction cleans up the entries for each scope.
|
||||
static void userEraseScope(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope on destruction, so we simply iterate.
|
||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ) {
|
||||
if (it->first.first == scopep) {
|
||||
s_s.m_userMap.erase(it++);
|
||||
} else {
|
||||
++it;
|
||||
}
|
||||
}
|
||||
}
|
||||
static void userDump() {
|
||||
bool first = true;
|
||||
for (UserMap::iterator it=s_s.m_userMap.begin(); it!=s_s.m_userMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF(" userDump:\n"); first=false; }
|
||||
VL_PRINTF(" DPI_USER_DATA scope %p key %p: %p\n",
|
||||
it->first.first, it->first.second, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - scope name
|
||||
static void scopeInsert(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope at construction
|
||||
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));
|
||||
}
|
||||
}
|
||||
static inline const VerilatedScope* scopeFind(const char* namep) {
|
||||
VerilatedScopeNameMap::iterator it=s_s.m_nameMap.find(namep);
|
||||
if (VL_LIKELY(it != s_s.m_nameMap.end())) return it->second;
|
||||
else return NULL;
|
||||
}
|
||||
static void scopeErase(const VerilatedScope* scopep) {
|
||||
// Slow ok - called once/scope at destruction
|
||||
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);
|
||||
}
|
||||
static void scopesDump() {
|
||||
VL_PRINTF(" scopesDump:\n");
|
||||
for (VerilatedScopeNameMap::iterator it=s_s.m_nameMap.begin(); it!=s_s.m_nameMap.end(); ++it) {
|
||||
const VerilatedScope* scopep = it->second;
|
||||
scopep->scopeDump();
|
||||
}
|
||||
VL_PRINTF("\n");
|
||||
}
|
||||
static const VerilatedScopeNameMap* scopeNameMap() {
|
||||
return &s_s.m_nameMap;
|
||||
}
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - export names
|
||||
|
||||
// Each function prototype is converted to a function number which we
|
||||
// then use to index a 2D table also indexed by scope number, because we
|
||||
// can't know at Verilation time what scopes will exist in other modules
|
||||
// in the design that also happen to have our same callback function.
|
||||
// Rather than a 2D map, the integer scheme saves 500ish ns on a likely
|
||||
// miss at the cost of a multiply, and all lookups move to slowpath.
|
||||
static int exportInsert(const char* namep) {
|
||||
// Slow ok - called once/function at creation
|
||||
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++;
|
||||
} else {
|
||||
return it->second;
|
||||
}
|
||||
}
|
||||
static int exportFind(const char* namep) {
|
||||
ExportNameMap::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");
|
||||
vl_fatal("unknown",0,"", msg.c_str());
|
||||
return -1;
|
||||
}
|
||||
static const char* exportName(int funcnum) {
|
||||
// Slowpath; find name for given export; errors only so no map to reverse-map it
|
||||
for (ExportNameMap::iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (it->second == funcnum) return it->first;
|
||||
}
|
||||
return "*UNKNOWN*";
|
||||
}
|
||||
static void exportsDump() {
|
||||
bool first = true;
|
||||
for (ExportNameMap::iterator it=s_s.m_exportMap.begin(); it!=s_s.m_exportMap.end(); ++it) {
|
||||
if (first) { VL_PRINTF(" exportDump:\n"); first=false; }
|
||||
VL_PRINTF(" DPI_EXPORT_NAME %05d: %s\n", it->second, it->first);
|
||||
}
|
||||
}
|
||||
// We don't free up m_exportMap until the end, because we can't be sure
|
||||
// what other models are using the assigned funcnum's.
|
||||
|
||||
public: // But only for verilated*.cpp
|
||||
// METHODS - file IO
|
||||
static IData fdNew(FILE* fp) {
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
// Bit 31 indicates it's a descriptor not a MCD
|
||||
if (s_s.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((IData)i);
|
||||
}
|
||||
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
|
||||
}
|
||||
static void fdDelete(IData fdi) {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<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 inline FILE* fdToFp(IData fdi) {
|
||||
IData idx = VL_MASK_I(31) & fdi;
|
||||
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
|
||||
return s_s.m_fdps[idx];
|
||||
}
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
@@ -0,0 +1,234 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief C++ Tracing in VCD Format
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_save.h"
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <cerrno>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifndef O_LARGEFILE // For example on WIN32
|
||||
# define O_LARGEFILE 0
|
||||
#endif
|
||||
#ifndef O_NONBLOCK
|
||||
# define O_NONBLOCK 0
|
||||
#endif
|
||||
|
||||
// CONSTANTS
|
||||
static const char* VLTSAVE_HEADER_STR = "verilatorsave01\n"; ///< Value of first bytes of each file
|
||||
static const char* VLTSAVE_TRAILER_STR = "vltsaved"; ///< Value of last bytes of each file
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Searalization
|
||||
|
||||
bool VerilatedDeserialize::readDiffers (const void* __restrict datap, size_t size) {
|
||||
bufferCheck();
|
||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||
vluint8_t miss = 0;
|
||||
while (size--) {
|
||||
miss |= (*dp++ ^ *m_cp++);
|
||||
}
|
||||
return (miss!=0);
|
||||
}
|
||||
|
||||
VerilatedDeserialize& VerilatedDeserialize::readAssert (const void* __restrict datap, size_t size) {
|
||||
if (VL_UNLIKELY(readDiffers(datap,size))) {
|
||||
std::string fn = filename();
|
||||
std::string msg = (std::string)"Can't deserialize save-restore file as was made from different model";
|
||||
vl_fatal(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
|
||||
void VerilatedSerialize::header() {
|
||||
VerilatedSerialize& os = *this; // So can cut and paste standard << code below
|
||||
assert((strlen(VLTSAVE_HEADER_STR) & 7) == 0); // Keep aligned
|
||||
os.write(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR));
|
||||
|
||||
// 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());
|
||||
}
|
||||
|
||||
void VerilatedDeserialize::header() {
|
||||
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";
|
||||
vl_fatal(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
|
||||
}
|
||||
|
||||
void VerilatedSerialize::trailer() {
|
||||
VerilatedSerialize& os = *this; // So can cut and paste standard << code below
|
||||
assert((strlen(VLTSAVE_TRAILER_STR) & 7) == 0); // Keep aligned
|
||||
os.write(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR));
|
||||
}
|
||||
|
||||
void VerilatedDeserialize::trailer() {
|
||||
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
|
||||
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";
|
||||
vl_fatal(fn.c_str(), 0, "", msg.c_str());
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Opening/Closing
|
||||
|
||||
void VerilatedSave::open (const char* filenamep) {
|
||||
if (isOpen()) return;
|
||||
VL_DEBUG_IF(VL_PRINTF("-vltSave: opening save file %s\n",filenamep););
|
||||
|
||||
if (filenamep[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
} else {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
m_fd = ::open (filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK
|
||||
, 0666);
|
||||
if (m_fd<0) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_isOpen = true;
|
||||
m_filename = filenamep;
|
||||
m_cp = m_bufp;
|
||||
header();
|
||||
}
|
||||
|
||||
void VerilatedRestore::open (const char* filenamep) {
|
||||
if (isOpen()) return;
|
||||
VL_DEBUG_IF(VL_PRINTF("-vltRestore: opening restore file %s\n",filenamep););
|
||||
|
||||
if (filenamep[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
} else {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
m_fd = ::open (filenamep, O_CREAT|O_RDONLY|O_LARGEFILE
|
||||
, 0666);
|
||||
if (m_fd<0) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_isOpen = true;
|
||||
m_filename = filenamep;
|
||||
m_cp = m_bufp;
|
||||
m_endp = m_bufp;
|
||||
header();
|
||||
}
|
||||
|
||||
void VerilatedSave::close () {
|
||||
if (!isOpen()) return;
|
||||
trailer();
|
||||
flush();
|
||||
m_isOpen = false;
|
||||
::close(m_fd); // May get error, just ignore it
|
||||
}
|
||||
|
||||
void VerilatedRestore::close () {
|
||||
if (!isOpen()) return;
|
||||
trailer();
|
||||
flush();
|
||||
m_isOpen = false;
|
||||
::close(m_fd); // May get error, just ignore it
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Buffer management
|
||||
|
||||
void VerilatedSave::flush() {
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
vluint8_t* wp = m_bufp;
|
||||
while (1) {
|
||||
ssize_t remaining = (m_cp - wp);
|
||||
if (remaining==0) break;
|
||||
errno = 0;
|
||||
ssize_t got = ::write (m_fd, wp, remaining);
|
||||
if (got>0) {
|
||||
wp += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
close();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_cp = m_bufp; // Reset buffer
|
||||
}
|
||||
|
||||
void VerilatedRestore::fill() {
|
||||
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
|
||||
m_endp = m_bufp + (m_endp - m_cp);
|
||||
m_cp = m_bufp; // Reset buffer
|
||||
// Read into buffer starting at m_endp
|
||||
while (1) {
|
||||
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) {
|
||||
m_endp += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = std::string(__FUNCTION__)+": "+strerror(errno);
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
close();
|
||||
break;
|
||||
}
|
||||
} 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';
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Serialization of types
|
||||
|
||||
|
||||
@@ -0,0 +1,233 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2012-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Save-restore serialization of verilated modules
|
||||
///
|
||||
//=============================================================================
|
||||
|
||||
#ifndef _VERILATED_SAVE_C_H_
|
||||
#define _VERILATED_SAVE_C_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSerialBase - internal base class for common code between VerilatedSerialize and VerilatedDeserialize
|
||||
|
||||
class VerilatedSerialBase {
|
||||
protected:
|
||||
// MEMBERS
|
||||
// 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
|
||||
std::string m_filename;
|
||||
|
||||
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
|
||||
inline static size_t bufferInsertSize() { return 16*1024; }
|
||||
|
||||
// CREATORS
|
||||
VerilatedSerialBase() {
|
||||
m_isOpen = false;
|
||||
m_bufp = new vluint8_t [bufferSize()];
|
||||
m_cp = m_bufp;
|
||||
}
|
||||
private:
|
||||
VerilatedSerialBase(const VerilatedSerialBase& ); ///< N/A, no copy constructor
|
||||
public:
|
||||
// CREATORS
|
||||
virtual ~VerilatedSerialBase() {
|
||||
close();
|
||||
if (m_bufp) { delete m_bufp; m_bufp=NULL; }
|
||||
}
|
||||
// METHODS
|
||||
bool isOpen() const { return m_isOpen; }
|
||||
std::string filename() const { return m_filename; }
|
||||
virtual void close() { flush(); }
|
||||
virtual void flush() {}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSerialize - convert structures to a stream representation
|
||||
|
||||
class VerilatedSerialize : public VerilatedSerialBase {
|
||||
protected:
|
||||
virtual void close() { flush(); }
|
||||
virtual void flush() {}
|
||||
void header();
|
||||
void trailer();
|
||||
public:
|
||||
// CREATORS
|
||||
VerilatedSerialize() {}
|
||||
virtual ~VerilatedSerialize() { close(); }
|
||||
// METHODS
|
||||
VerilatedSerialize& bufferCheck() {
|
||||
// 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();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
inline VerilatedSerialize& write (const void* __restrict datap, size_t size) {
|
||||
const vluint8_t* __restrict dp = (const vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||
const vluint8_t* __restrict maxp = dp + blk;
|
||||
while (dp < maxp) *m_cp++ = *dp++;
|
||||
size -= blk;
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedDeserial - load structures from a stream representation
|
||||
|
||||
class VerilatedDeserialize : public VerilatedSerialBase {
|
||||
protected:
|
||||
vluint8_t* m_endp; ///< Last valid byte in m_bufp buffer
|
||||
virtual void fill() = 0;
|
||||
void header();
|
||||
void trailer();
|
||||
public:
|
||||
// CREATORS
|
||||
VerilatedDeserialize() { m_endp = NULL; }
|
||||
virtual ~VerilatedDeserialize() { close(); }
|
||||
// METHODS
|
||||
inline VerilatedDeserialize& read (void* __restrict datap, size_t size) {
|
||||
vluint8_t* __restrict dp = (vluint8_t* __restrict)datap;
|
||||
while (size) {
|
||||
bufferCheck();
|
||||
size_t blk = size; if (blk>bufferInsertSize()) blk = bufferInsertSize();
|
||||
const vluint8_t* __restrict maxp = dp + blk;
|
||||
while (dp < maxp) *dp++ = *m_cp++;
|
||||
size -= blk;
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
// Read a datum and compare with expected value
|
||||
bool readDiffers (const void* __restrict datap, size_t size);
|
||||
VerilatedDeserialize& readAssert (const void* __restrict datap, size_t size);
|
||||
VerilatedDeserialize& readAssert (vluint64_t data) { return readAssert(&data, sizeof(data)); }
|
||||
VerilatedDeserialize& bufferCheck() {
|
||||
// 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();
|
||||
}
|
||||
return *this; // For function chaining
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedSave - serialize to a file
|
||||
|
||||
class VerilatedSave : public VerilatedSerialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
VerilatedSave() { m_fd=-1; }
|
||||
virtual ~VerilatedSave() { close(); }
|
||||
// METHODS
|
||||
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) { open(filename.c_str()); }
|
||||
virtual void close();
|
||||
virtual void flush();
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedRestore - deserialize from a file
|
||||
|
||||
class VerilatedRestore : public VerilatedDeserialize {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
VerilatedRestore() { m_fd=-1; }
|
||||
virtual ~VerilatedRestore() { close(); }
|
||||
|
||||
// METHODS
|
||||
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
|
||||
void open(const std::string& filename) { open(filename.c_str()); }
|
||||
virtual void close();
|
||||
virtual void flush() {}
|
||||
virtual void fill();
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint64_t& rhs) {
|
||||
return os.write(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint64_t& rhs){
|
||||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint32_t& rhs) {
|
||||
return os.write(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint32_t& rhs) {
|
||||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint16_t& rhs) {
|
||||
return os.write(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint16_t& rhs) {
|
||||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, vluint8_t& rhs) {
|
||||
return os.write(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, vluint8_t& rhs) {
|
||||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, bool& rhs) {
|
||||
return os.write(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, bool& rhs) {
|
||||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, double& rhs) {
|
||||
return os.write(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, double& rhs) {
|
||||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, float& rhs) {
|
||||
return os.write(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, float& rhs) {
|
||||
return os.read(&rhs, sizeof(rhs));
|
||||
}
|
||||
inline VerilatedSerialize& operator<<(VerilatedSerialize& os, std::string& rhs) {
|
||||
vluint32_t len=rhs.length();
|
||||
os<<len;
|
||||
return os.write(rhs.data(), len);
|
||||
}
|
||||
inline VerilatedDeserialize& operator>>(VerilatedDeserialize& os, std::string& rhs) {
|
||||
vluint32_t len=0;
|
||||
os>>len;
|
||||
rhs.resize(len);
|
||||
return os.read((void*)rhs.data(), len);
|
||||
}
|
||||
|
||||
#endif // guard
|
||||
@@ -1,7 +1,7 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2009-2017 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.
|
||||
@@ -24,8 +24,8 @@
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATEDSC_H_
|
||||
#define _VERILATEDSC_H_ 1 ///< Header Guard
|
||||
#ifndef _VERILATED_SC_H_
|
||||
#define _VERILATED_SC_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "systemc.h"
|
||||
@@ -39,9 +39,9 @@
|
||||
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
|
||||
class VlScBvExposer : public sc_bv_base {
|
||||
public:
|
||||
static uint32_t* sp_datap(const sc_bv_base& base) {
|
||||
static vluint32_t* sp_datap(const sc_bv_base& base) {
|
||||
return static_cast<const VlScBvExposer*>(&base)->sp_datatp(); }
|
||||
uint32_t* sp_datatp() const { return (uint32_t*)(m_data); }
|
||||
vluint32_t* sp_datatp() const { return (vluint32_t*)(m_data); }
|
||||
// Above reads this protected element in sc_bv_base:
|
||||
// sc_digit* m_data; // data array
|
||||
};
|
||||
@@ -0,0 +1,107 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: Include to allow symbol inspection
|
||||
///
|
||||
/// This file is for inclusion by files that need to inspect
|
||||
/// the symbol table. It is not included in verilated.h
|
||||
/// as it requires some heavyweight C++ classes.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//*************************************************************************
|
||||
|
||||
|
||||
#ifndef _VERILATED_SYMS_H_
|
||||
#define _VERILATED_SYMS_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilated_heavy.h"
|
||||
|
||||
#include <map>
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator range
|
||||
|
||||
// See also V3Ast::VNumRange
|
||||
class VerilatedRange {
|
||||
int m_left;
|
||||
int m_right;
|
||||
protected:
|
||||
friend class VerilatedVar;
|
||||
friend class VerilatedScope;
|
||||
VerilatedRange() : m_left(0), m_right(0) {}
|
||||
void sets(int left, int right) { m_left=left; m_right=right; }
|
||||
public:
|
||||
~VerilatedRange() {}
|
||||
int left() const { return m_left; }
|
||||
int right() const { return m_right; }
|
||||
int elements() const { return (VL_LIKELY(m_left>=m_right)?(m_left-m_right+1):(m_right-m_left+1)); }
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
/// Verilator variable
|
||||
|
||||
class VerilatedVar {
|
||||
void* m_datap; // Location of data
|
||||
VerilatedVarType m_vltype; // Data type
|
||||
VerilatedVarFlags m_vlflags; // Direction
|
||||
VerilatedRange m_range; // First range
|
||||
VerilatedRange m_array; // Array
|
||||
int m_dims; // Dimensions
|
||||
const char* m_namep; // Name - slowpath
|
||||
protected:
|
||||
friend class VerilatedScope;
|
||||
VerilatedVar(const char* namep, void* datap,
|
||||
VerilatedVarType vltype, VerilatedVarFlags vlflags, int dims)
|
||||
: m_datap(datap), m_vltype(vltype), m_vlflags(vlflags), m_dims(dims), m_namep(namep) {}
|
||||
public:
|
||||
~VerilatedVar() {}
|
||||
void* datap() const { return m_datap; }
|
||||
VerilatedVarType vltype() const { return m_vltype; }
|
||||
VerilatedVarFlags vldir() const { return (VerilatedVarFlags)((int)m_vlflags & VLVF_MASK_DIR); }
|
||||
vluint32_t entSize() const;
|
||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||
const VerilatedRange& range() const { return m_range; }
|
||||
const VerilatedRange& array() const { return m_array; }
|
||||
const char* name() const { return m_namep; }
|
||||
int dims() const { return m_dims; }
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
/// Types
|
||||
|
||||
struct VerilatedCStrCmp {
|
||||
/// Ordering maps keyed by const char*'s
|
||||
bool operator() (const char *a, const char *b) const {
|
||||
return std::strcmp(a, b) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedScopeNameMap
|
||||
: public std::map<const char*, const VerilatedScope*, VerilatedCStrCmp> {
|
||||
public:
|
||||
VerilatedScopeNameMap() {}
|
||||
~VerilatedScopeNameMap() {}
|
||||
};
|
||||
|
||||
class VerilatedVarNameMap
|
||||
: public std::map<const char*, VerilatedVar, VerilatedCStrCmp> {
|
||||
public:
|
||||
VerilatedVarNameMap() {}
|
||||
~VerilatedVarNameMap() {}
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
@@ -0,0 +1,753 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief C++ Tracing in VCD Format
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <cerrno>
|
||||
#include <ctime>
|
||||
#include <algorithm>
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
|
||||
# include <io.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
// SPDIFF_ON
|
||||
|
||||
#ifndef O_LARGEFILE // For example on WIN32
|
||||
# define O_LARGEFILE 0
|
||||
#endif
|
||||
#ifndef O_NONBLOCK
|
||||
# define O_NONBLOCK 0
|
||||
#endif
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdCallInfo
|
||||
/// Internal callback routines for each module being traced.
|
||||
////
|
||||
/// Each module that wishes to be traced registers a set of
|
||||
/// callbacks stored in this class. When the trace file is being
|
||||
/// constructed, this class provides the callback routines to be executed.
|
||||
|
||||
class VerilatedVcdCallInfo {
|
||||
protected:
|
||||
friend class VerilatedVcd;
|
||||
VerilatedVcdCallback_t m_initcb; ///< Initialization Callback function
|
||||
VerilatedVcdCallback_t m_fullcb; ///< Full Dumping Callback function
|
||||
VerilatedVcdCallback_t m_changecb; ///< Incremental Dumping Callback function
|
||||
void* m_userthis; ///< Fake "this" for caller
|
||||
vluint32_t m_code; ///< Starting code number
|
||||
// CREATORS
|
||||
VerilatedVcdCallInfo (VerilatedVcdCallback_t icb, VerilatedVcdCallback_t fcb,
|
||||
VerilatedVcdCallback_t changecb,
|
||||
void* ut, vluint32_t code)
|
||||
: m_initcb(icb), m_fullcb(fcb), m_changecb(changecb), m_userthis(ut), m_code(code) {};
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// VerilatedVcdFile
|
||||
|
||||
bool VerilatedVcdFile::open(const std::string& name) {
|
||||
m_fd = ::open(name.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK, 0666);
|
||||
return (m_fd>=0);
|
||||
}
|
||||
|
||||
void VerilatedVcdFile::close() {
|
||||
::close(m_fd);
|
||||
}
|
||||
|
||||
ssize_t VerilatedVcdFile::write(const char* bufp, ssize_t len) {
|
||||
return ::write(m_fd, bufp, len);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
//=============================================================================
|
||||
// Opening/Closing
|
||||
|
||||
VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep)
|
||||
: m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) {
|
||||
// Not in header to avoid link issue if header is included without this .cpp file
|
||||
m_fileNewed = (filep == NULL);
|
||||
m_filep = m_fileNewed ? new VerilatedVcdFile : filep;
|
||||
m_namemapp = NULL;
|
||||
m_timeRes = m_timeUnit = 1e-9;
|
||||
m_timeLastDump = 0;
|
||||
m_sigs_oldvalp = NULL;
|
||||
m_evcd = false;
|
||||
m_scopeEscape = '.'; // Backward compatibility
|
||||
m_fullDump = true;
|
||||
m_wrChunkSize = 8*1024;
|
||||
m_wrBufp = new char [m_wrChunkSize*8];
|
||||
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
|
||||
m_writep = m_wrBufp;
|
||||
m_wroteBytes = 0;
|
||||
}
|
||||
|
||||
void VerilatedVcd::open (const char* filename) {
|
||||
if (isOpen()) return;
|
||||
|
||||
// Set member variables
|
||||
m_filename = filename;
|
||||
singleton().s_vcdVecp.push_back(this);
|
||||
|
||||
// SPDIFF_OFF
|
||||
// Set callback so an early exit will flush us
|
||||
Verilated::flushCb(&flush_all);
|
||||
|
||||
// SPDIFF_ON
|
||||
openNext (m_rolloverMB!=0);
|
||||
if (!isOpen()) return;
|
||||
|
||||
dumpHeader();
|
||||
|
||||
// Allocate space now we know the number of codes
|
||||
if (!m_sigs_oldvalp) {
|
||||
m_sigs_oldvalp = new vluint32_t [m_nextCode+10];
|
||||
}
|
||||
|
||||
if (m_rolloverMB) {
|
||||
openNext(true);
|
||||
if (!isOpen()) return;
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::openNext (bool incFilename) {
|
||||
// Open next filename in concat sequence, mangle filename if
|
||||
// incFilename is true.
|
||||
closePrev(); // Close existing
|
||||
if (incFilename) {
|
||||
// Find _0000.{ext} in filename
|
||||
std::string name = m_filename;
|
||||
size_t pos=name.rfind(".");
|
||||
if (pos>8 && 0==strncmp("_cat",name.c_str()+pos-8,4)
|
||||
&& isdigit(name.c_str()[pos-4])
|
||||
&& isdigit(name.c_str()[pos-3])
|
||||
&& isdigit(name.c_str()[pos-2])
|
||||
&& isdigit(name.c_str()[pos-1])) {
|
||||
// Increment code.
|
||||
if ((++(name[pos-1])) > '9') {
|
||||
name[pos-1] = '0';
|
||||
if ((++(name[pos-2])) > '9') {
|
||||
name[pos-2] = '0';
|
||||
if ((++(name[pos-3])) > '9') {
|
||||
name[pos-3] = '0';
|
||||
if ((++(name[pos-4])) > '9') {
|
||||
name[pos-4] = '0';
|
||||
}}}}
|
||||
} else {
|
||||
// Append _cat0000
|
||||
name.insert(pos,"_cat0000");
|
||||
}
|
||||
m_filename = name;
|
||||
}
|
||||
if (m_filename[0]=='|') {
|
||||
assert(0); // Not supported yet.
|
||||
} else {
|
||||
// cppcheck-suppress duplicateExpression
|
||||
if (!m_filep->open(m_filename)) {
|
||||
// User code can check isOpen()
|
||||
m_isOpen = false;
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_isOpen = true;
|
||||
m_fullDump = true; // First dump must be full
|
||||
m_wroteBytes = 0;
|
||||
}
|
||||
|
||||
void VerilatedVcd::makeNameMap() {
|
||||
// Take signal information from each module and build m_namemapp
|
||||
deleteNameMap();
|
||||
m_nextCode = 1;
|
||||
m_namemapp = new NameMap;
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
cip->m_code = nextCode();
|
||||
(cip->m_initcb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
|
||||
// Though not speced, it's illegal to generate a vcd with signals
|
||||
// not under any module - it crashes at least two viewers.
|
||||
// If no scope was specified, prefix everything with a "top"
|
||||
// This comes from user instantiations with no name - IE Vtop("").
|
||||
bool nullScope = false;
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const std::string& hiername = it->first;
|
||||
if (hiername.size() >= 1 && hiername[0] == '\t') nullScope=true;
|
||||
}
|
||||
if (nullScope) {
|
||||
NameMap* newmapp = new NameMap;
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const std::string& hiername = it->first;
|
||||
const std::string& decl = it->second;
|
||||
std::string newname = std::string("top");
|
||||
if (hiername[0] != '\t') newname += ' ';
|
||||
newname += hiername;
|
||||
newmapp->insert(std::make_pair(newname,decl));
|
||||
}
|
||||
deleteNameMap();
|
||||
m_namemapp = newmapp;
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::deleteNameMap() {
|
||||
if (m_namemapp) { delete m_namemapp; m_namemapp=NULL; }
|
||||
}
|
||||
|
||||
VerilatedVcd::~VerilatedVcd() {
|
||||
close();
|
||||
if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; }
|
||||
if (m_sigs_oldvalp) { delete[] m_sigs_oldvalp; m_sigs_oldvalp=NULL; }
|
||||
deleteNameMap();
|
||||
if (m_filep && m_fileNewed) { delete m_filep; m_filep = NULL; }
|
||||
// Remove from list of traces
|
||||
VcdVec::iterator pos = find(singleton().s_vcdVecp.begin(), singleton().s_vcdVecp.end(), this);
|
||||
if (pos != singleton().s_vcdVecp.end()) { singleton().s_vcdVecp.erase(pos); }
|
||||
}
|
||||
|
||||
void VerilatedVcd::closePrev () {
|
||||
if (!isOpen()) return;
|
||||
|
||||
bufferFlush();
|
||||
m_isOpen = false;
|
||||
m_filep->close();
|
||||
}
|
||||
|
||||
void VerilatedVcd::closeErr () {
|
||||
// Close due to an error. We might abort before even getting here,
|
||||
// depending on the definition of vl_fatal.
|
||||
if (!isOpen()) return;
|
||||
|
||||
// No buffer flush, just fclose
|
||||
m_isOpen = false;
|
||||
m_filep->close(); // May get error, just ignore it
|
||||
}
|
||||
|
||||
void VerilatedVcd::close() {
|
||||
if (!isOpen()) return;
|
||||
if (m_evcd) {
|
||||
printStr("$vcdclose ");
|
||||
printTime(m_timeLastDump);
|
||||
printStr(" $end\n");
|
||||
}
|
||||
closePrev();
|
||||
}
|
||||
|
||||
void VerilatedVcd::printStr (const char* str) {
|
||||
// Not fast...
|
||||
while (*str) {
|
||||
*m_writep++ = *str++;
|
||||
bufferCheck();
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::printQuad (vluint64_t n) {
|
||||
char buf [100];
|
||||
sprintf(buf,"%" VL_PRI64 "u", n);
|
||||
printStr(buf);
|
||||
}
|
||||
|
||||
void VerilatedVcd::printTime (vluint64_t timeui) {
|
||||
// VCD file format specification does not allow non-integers for timestamps
|
||||
// Dinotrace doesn't mind, but Cadence vvision seems to choke
|
||||
if (VL_UNLIKELY(timeui < m_timeLastDump)) {
|
||||
timeui = m_timeLastDump;
|
||||
static bool backTime = false;
|
||||
if (!backTime) {
|
||||
backTime = true;
|
||||
VL_PRINTF("VCD time is moving backwards, wave file may be incorrect.\n");
|
||||
}
|
||||
}
|
||||
m_timeLastDump = timeui;
|
||||
printQuad(timeui);
|
||||
}
|
||||
|
||||
void VerilatedVcd::bufferResize(vluint64_t minsize) {
|
||||
// minsize is size of largest write. We buffer at least 8 times as much data,
|
||||
// writing when we are 3/4 full (with thus 2*minsize remaining free)
|
||||
if (VL_UNLIKELY(minsize > m_wrChunkSize)) {
|
||||
char* oldbufp = m_wrBufp;
|
||||
m_wrChunkSize = minsize*2;
|
||||
m_wrBufp = new char [m_wrChunkSize * 8];
|
||||
memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
|
||||
m_writep = m_wrBufp + (m_writep - oldbufp);
|
||||
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
|
||||
delete oldbufp; oldbufp=NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void VerilatedVcd::bufferFlush () {
|
||||
// We add output data to m_writep.
|
||||
// When it gets nearly full we dump it using this routine which calls write()
|
||||
// This is much faster than using buffered I/O
|
||||
if (VL_UNLIKELY(!isOpen())) return;
|
||||
char* wp = m_wrBufp;
|
||||
while (1) {
|
||||
ssize_t remaining = (m_writep - wp);
|
||||
if (remaining==0) break;
|
||||
errno = 0;
|
||||
ssize_t got = m_filep->write(wp, remaining);
|
||||
if (got>0) {
|
||||
wp += got;
|
||||
m_wroteBytes += got;
|
||||
} else if (got < 0) {
|
||||
if (errno != EAGAIN && errno != EINTR) {
|
||||
// write failed, presume error (perhaps out of disk space)
|
||||
std::string msg = (std::string)"VerilatedVcd::bufferFlush: "+strerror(errno);
|
||||
vl_fatal("",0,"",msg.c_str());
|
||||
closeErr();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset buffer
|
||||
m_writep = m_wrBufp;
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Simple methods
|
||||
|
||||
void VerilatedVcd::set_time_unit (const char* unitp) {
|
||||
//cout<<" set_time_unit ("<<unitp<<") == "<<timescaleToDouble(unitp)<<" == "<<doubleToTimescale(timescaleToDouble(unitp))<<endl;
|
||||
m_timeUnit = timescaleToDouble(unitp);
|
||||
}
|
||||
|
||||
void VerilatedVcd::set_time_resolution (const char* unitp) {
|
||||
//cout<<"set_time_resolution ("<<unitp<<") == "<<timescaleToDouble(unitp)<<" == "<<doubleToTimescale(timescaleToDouble(unitp))<<endl;
|
||||
m_timeRes = timescaleToDouble(unitp);
|
||||
}
|
||||
|
||||
double VerilatedVcd::timescaleToDouble (const char* unitp) {
|
||||
char* endp;
|
||||
double value = strtod(unitp, &endp);
|
||||
if (!value) value=1; // On error so we allow just "ns" to return 1e-9.
|
||||
unitp=endp;
|
||||
while (*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;
|
||||
}
|
||||
|
||||
std::string VerilatedVcd::doubleToTimescale (double value) {
|
||||
const char* suffixp = "s";
|
||||
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; }
|
||||
char valuestr[100]; sprintf(valuestr,"%3.0f%s", value, suffixp);
|
||||
return valuestr; // Gets converted to string, so no ref to stack
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Definitions
|
||||
|
||||
void VerilatedVcd::printIndent (int level_change) {
|
||||
if (level_change<0) m_modDepth += level_change;
|
||||
assert(m_modDepth>=0);
|
||||
for (int i=0; i<m_modDepth; i++) printStr(" ");
|
||||
if (level_change>0) m_modDepth += level_change;
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpHeader () {
|
||||
printStr("$version Generated by VerilatedVcd $end\n");
|
||||
time_t time_str = time(NULL);
|
||||
printStr("$date "); printStr(ctime(&time_str)); printStr(" $end\n");
|
||||
|
||||
printStr("$timescale ");
|
||||
const std::string& timeResStr = doubleToTimescale(m_timeRes);
|
||||
printStr(timeResStr.c_str());
|
||||
printStr(" $end\n");
|
||||
|
||||
makeNameMap();
|
||||
|
||||
// Signal header
|
||||
assert (m_modDepth==0);
|
||||
printIndent(1);
|
||||
printStr("\n");
|
||||
|
||||
// We detect the spaces in module names to determine hierarchy. This
|
||||
// allows signals to be declared without fixed ordering, which is
|
||||
// required as Verilog signals might be separately declared from
|
||||
// SC module signals.
|
||||
|
||||
// Print the signal names
|
||||
const char* lastName = "";
|
||||
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
|
||||
const std::string& hiernamestr = it->first;
|
||||
const std::string& decl = it->second;
|
||||
|
||||
// Determine difference between the old and new names
|
||||
const char* hiername = hiernamestr.c_str();
|
||||
const char* lp = lastName;
|
||||
const char* np = hiername;
|
||||
lastName = hiername;
|
||||
|
||||
// Skip common prefix, it must break at a space or tab
|
||||
for (; *np && (*np == *lp); np++, lp++) {}
|
||||
while (np!=hiername && *np && *np!=' ' && *np!='\t') { np--; lp--; }
|
||||
//printf("hier %s\n lp=%s\n np=%s\n",hiername,lp,np);
|
||||
|
||||
// Any extra spaces in last name are scope ups we need to do
|
||||
bool first = true;
|
||||
for (; *lp; lp++) {
|
||||
if (*lp==' ' || (first && *lp!='\t')) {
|
||||
printIndent(-1);
|
||||
printStr("$upscope $end\n");
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
|
||||
// Any new spaces are scope downs we need to do
|
||||
while (*np) {
|
||||
if (*np==' ') np++;
|
||||
if (*np=='\t') break; // tab means signal name starts
|
||||
printIndent(1);
|
||||
printStr("$scope module ");
|
||||
for (; *np && *np!=' ' && *np!='\t'; np++) {
|
||||
if (*np=='[') printStr("(");
|
||||
else if (*np==']') printStr(")");
|
||||
else *m_writep++=*np;
|
||||
}
|
||||
printStr(" $end\n");
|
||||
}
|
||||
|
||||
printIndent(0);
|
||||
printStr(decl.c_str());
|
||||
}
|
||||
|
||||
while (m_modDepth>1) {
|
||||
printIndent(-1);
|
||||
printStr("$upscope $end\n");
|
||||
}
|
||||
|
||||
printIndent(-1);
|
||||
printStr("$enddefinitions $end\n\n\n");
|
||||
assert (m_modDepth==0);
|
||||
|
||||
// Reclaim storage
|
||||
deleteNameMap();
|
||||
}
|
||||
|
||||
void VerilatedVcd::module (const std::string& name) {
|
||||
m_modName = name;
|
||||
}
|
||||
|
||||
void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep,
|
||||
int arraynum, bool tri, bool bussed, int msb, int lsb) {
|
||||
if (!code) { vl_fatal(__FILE__,__LINE__,"","Internal: internal trace problem, code 0 is illegal"); }
|
||||
|
||||
int bits = ((msb>lsb)?(msb-lsb):(lsb-msb))+1;
|
||||
int codesNeeded = 1+int(bits/32);
|
||||
if (tri) codesNeeded *= 2; // Space in change array for __en signals
|
||||
|
||||
// Make sure array is large enough
|
||||
m_nextCode = std::max(nextCode(), code+codesNeeded);
|
||||
if (m_sigs.capacity() <= m_nextCode) {
|
||||
m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up
|
||||
}
|
||||
|
||||
// Make sure write buffer is large enough (one character per bit), plus header
|
||||
bufferResize(bits+1024);
|
||||
|
||||
// Save declaration info
|
||||
VerilatedVcdSig sig = VerilatedVcdSig(code, bits);
|
||||
m_sigs.push_back(sig);
|
||||
|
||||
// Split name into basename
|
||||
// Spaces and tabs aren't legal in VCD signal names, so:
|
||||
// Space separates each level of scope
|
||||
// Tab separates final scope from signal name
|
||||
// Tab sorts before spaces, so signals nicely will print before scopes
|
||||
// Note the hiername may be nothing, if so we'll add "\t{name}"
|
||||
std::string nameasstr = name;
|
||||
if (m_modName!="") { nameasstr = m_modName+m_scopeEscape+nameasstr; } // Optional ->module prefix
|
||||
std::string hiername;
|
||||
std::string basename;
|
||||
for (const char* cp=nameasstr.c_str(); *cp; cp++) {
|
||||
if (isScopeEscape(*cp)) {
|
||||
// Ahh, we've just read a scope, not a basename
|
||||
if (hiername!="") hiername += " ";
|
||||
hiername += basename;
|
||||
basename = "";
|
||||
} else {
|
||||
basename += *cp;
|
||||
}
|
||||
}
|
||||
hiername += "\t"+basename;
|
||||
|
||||
// Print reference
|
||||
std::string decl = "$var ";
|
||||
if (m_evcd) decl += "port"; else decl += wirep; // usually "wire"
|
||||
char buf [1000];
|
||||
sprintf(buf, " %2d ", bits);
|
||||
decl += buf;
|
||||
if (m_evcd) {
|
||||
sprintf(buf, "<%d", code);
|
||||
decl += buf;
|
||||
} else {
|
||||
decl += stringCode(code);
|
||||
}
|
||||
decl += " ";
|
||||
decl += basename;
|
||||
if (arraynum>=0) {
|
||||
sprintf(buf, "(%d)", arraynum);
|
||||
decl += buf;
|
||||
hiername += buf;
|
||||
}
|
||||
if (bussed) {
|
||||
sprintf(buf, " [%d:%d]", msb, lsb);
|
||||
decl += buf;
|
||||
}
|
||||
decl += " $end\n";
|
||||
m_namemapp->insert(std::make_pair(hiername,decl));
|
||||
}
|
||||
|
||||
void VerilatedVcd::declBit (vluint32_t code, const char* name, int arraynum)
|
||||
{ declare (code, name, "wire", arraynum, false, false, 0, 0); }
|
||||
void VerilatedVcd::declBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, false, true, msb, lsb); }
|
||||
void VerilatedVcd::declQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, false, true, msb, lsb); }
|
||||
void VerilatedVcd::declArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, false, true, msb, lsb); }
|
||||
void VerilatedVcd::declTriBit (vluint32_t code, const char* name, int arraynum)
|
||||
{ declare (code, name, "wire", arraynum, true, false, 0, 0); }
|
||||
void VerilatedVcd::declTriBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, true, true, msb, lsb); }
|
||||
void VerilatedVcd::declTriQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, true, true, msb, lsb); }
|
||||
void VerilatedVcd::declTriArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb)
|
||||
{ declare (code, name, "wire", arraynum, true, true, msb, lsb); }
|
||||
void VerilatedVcd::declFloat (vluint32_t code, const char* name, int arraynum)
|
||||
{ declare (code, name, "real", arraynum, false, false, 31, 0); }
|
||||
void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum)
|
||||
{ declare (code, name, "real", arraynum, false, false, 63, 0); }
|
||||
|
||||
//=============================================================================
|
||||
|
||||
void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
(*((double*)&m_sigs_oldvalp[code])) = newval;
|
||||
// Buffer can't overflow before sprintf; we sized during declaration
|
||||
sprintf(m_writep, "r%.16g", newval);
|
||||
m_writep += strlen(m_writep);
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void VerilatedVcd::fullFloat (vluint32_t code, const float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
(*((float*)&m_sigs_oldvalp[code])) = newval;
|
||||
// Buffer can't overflow before sprintf; we sized during declaration
|
||||
sprintf(m_writep, "r%.16g", (double)newval);
|
||||
m_writep += strlen(m_writep);
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Callbacks
|
||||
|
||||
void VerilatedVcd::addCallback (
|
||||
VerilatedVcdCallback_t initcb, VerilatedVcdCallback_t fullcb, VerilatedVcdCallback_t changecb,
|
||||
void* userthis)
|
||||
{
|
||||
if (VL_UNLIKELY(isOpen())) {
|
||||
std::string msg = (std::string)"Internal: "+__FILE__+"::"+__FUNCTION__+" called with already open file";
|
||||
vl_fatal(__FILE__,__LINE__,"",msg.c_str());
|
||||
}
|
||||
VerilatedVcdCallInfo* vci = new VerilatedVcdCallInfo(initcb, fullcb, changecb, userthis, nextCode());
|
||||
m_callbacks.push_back(vci);
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Dumping
|
||||
|
||||
void VerilatedVcd::dumpFull (vluint64_t timeui) {
|
||||
dumpPrep (timeui);
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
(cip->m_fullcb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
dumpDone ();
|
||||
}
|
||||
|
||||
void VerilatedVcd::dump (vluint64_t timeui) {
|
||||
if (!isOpen()) return;
|
||||
if (VL_UNLIKELY(m_fullDump)) {
|
||||
m_fullDump = false; // No need for more full dumps
|
||||
dumpFull(timeui);
|
||||
return;
|
||||
}
|
||||
if (VL_UNLIKELY(m_rolloverMB && m_wroteBytes > this->m_rolloverMB)) {
|
||||
openNext(true);
|
||||
if (!isOpen()) return;
|
||||
}
|
||||
dumpPrep (timeui);
|
||||
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
|
||||
VerilatedVcdCallInfo *cip = m_callbacks[ent];
|
||||
(cip->m_changecb) (this, cip->m_userthis, cip->m_code);
|
||||
}
|
||||
dumpDone();
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpPrep (vluint64_t timeui) {
|
||||
printStr("#");
|
||||
printTime(timeui);
|
||||
printStr("\n");
|
||||
}
|
||||
|
||||
void VerilatedVcd::dumpDone () {
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Static members
|
||||
|
||||
void VerilatedVcd::flush_all() {
|
||||
for (vluint32_t ent = 0; ent< singleton().s_vcdVecp.size(); ent++) {
|
||||
VerilatedVcd* vcdp = singleton().s_vcdVecp[ent];
|
||||
vcdp->flush();
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
|
||||
#ifdef VERILATED_VCD_TEST
|
||||
vluint32_t v1, v2, s1, s2[3];
|
||||
vluint32_t tri96[3];
|
||||
vluint32_t tri96__tri[3];
|
||||
vluint8_t ch;
|
||||
vluint64_t timestamp = 1;
|
||||
double doub = 0;
|
||||
|
||||
void vcdInit (VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
||||
vcdp->scopeEscape('.');
|
||||
vcdp->module ("top");
|
||||
vcdp->declBus (0x2, "v1",-1,5,1);
|
||||
vcdp->declBus (0x3, "v2",-1,6,0);
|
||||
vcdp->module ("top.sub1");
|
||||
vcdp->declBit (0x4, "s1",-1);
|
||||
vcdp->declBit (0x5, "ch",-1);
|
||||
vcdp->module ("top.sub2");
|
||||
vcdp->declArray (0x6, "s2",-1, 40,3);
|
||||
// Note need to add 3 for next code.
|
||||
vcdp->module ("top2");
|
||||
vcdp->declBus (0x2, "t2v1",-1,4,1);
|
||||
vcdp->declTriBit (0x10, "io1", -1);
|
||||
vcdp->declTriBus (0x12, "io5", -1,4,0);
|
||||
vcdp->declTriArray (0x16, "io96",-1,95,0);
|
||||
// Note need to add 6 for next code.
|
||||
vcdp->declDouble (0x1c, "doub",-1);
|
||||
// Note need to add 2 for next code.
|
||||
}
|
||||
|
||||
void vcdFull (VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
||||
vcdp->fullBus (0x2, v1,5);
|
||||
vcdp->fullBus (0x3, v2,7);
|
||||
vcdp->fullBit (0x4, s1);
|
||||
vcdp->fullBus (0x5, ch,2);
|
||||
vcdp->fullArray(0x6, &s2[0], 38);
|
||||
vcdp->fullTriBit (0x10, tri96[0]&1, tri96__tri[0]&1);
|
||||
vcdp->fullTriBus (0x12, tri96[0]&0x1f, tri96__tri[0]&0x1f, 5);
|
||||
vcdp->fullTriArray (0x16, tri96, tri96__tri, 96);
|
||||
vcdp->fullDouble(0x1c, doub);
|
||||
}
|
||||
|
||||
void vcdChange (VerilatedVcd* vcdp, void* userthis, vluint32_t code) {
|
||||
vcdp->chgBus (0x2, v1,5);
|
||||
vcdp->chgBus (0x3, v2,7);
|
||||
vcdp->chgBit (0x4, s1);
|
||||
vcdp->chgBus (0x5, ch,2);
|
||||
vcdp->chgArray(0x6, &s2[0], 38);
|
||||
vcdp->chgTriBit (0x10, tri96[0]&1, tri96__tri[0]&1);
|
||||
vcdp->chgTriBus (0x12, tri96[0]&0x1f, tri96__tri[0]&0x1f, 5);
|
||||
vcdp->chgTriArray (0x16, tri96, tri96__tri, 96);
|
||||
vcdp->chgDouble (0x1c, doub);
|
||||
}
|
||||
|
||||
main() {
|
||||
cout<<"test: O_LARGEFILE="<<O_LARGEFILE<<endl;
|
||||
|
||||
v1 = v2 = s1 = 0;
|
||||
s2[0] = s2[1] = s2[2] = 0;
|
||||
tri96[2] = tri96[1] = tri96[0] = 0;
|
||||
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0;
|
||||
ch = 0;
|
||||
doub = 0;
|
||||
{
|
||||
VerilatedVcdC* vcdp = new VerilatedVcdC;
|
||||
vcdp->spTrace()->addCallback (&vcdInit, &vcdFull, &vcdChange, 0);
|
||||
vcdp->open ("test.vcd");
|
||||
// Dumping
|
||||
vcdp->dump(timestamp++);
|
||||
v1 = 0xfff;
|
||||
tri96[2] = 4; tri96[1] = 2; tri96[0] = 1;
|
||||
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = ~0; // Still tri
|
||||
doub = 1.5;
|
||||
vcdp->dump(timestamp++);
|
||||
v2 = 0x1;
|
||||
s2[1] = 2;
|
||||
tri96__tri[2] = tri96__tri[1] = tri96__tri[0] = 0; // enable w/o data change
|
||||
doub = -1.66e13;
|
||||
vcdp->dump(timestamp++);
|
||||
ch = 2;
|
||||
tri96[2] = ~4; tri96[1] = ~2; tri96[0] = ~1;
|
||||
doub = -3.33e-13;
|
||||
vcdp->dump(timestamp++);
|
||||
vcdp->dump(timestamp++);
|
||||
# ifdef VERILATED_VCD_TEST_64BIT
|
||||
vluint64_t bytesPerDump = 15ULL;
|
||||
for (vluint64_t i=0; i<((1ULL<<32) / bytesPerDump); i++) {
|
||||
v1 = i;
|
||||
vcdp->dump(timestamp++);
|
||||
}
|
||||
# endif
|
||||
vcdp->close();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
//********************************************************************
|
||||
// Local Variables:
|
||||
// compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../src/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
|
||||
// End:
|
||||
@@ -0,0 +1,450 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief C++ Tracing in VCD Format
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#ifndef _VERILATED_VCD_C_H_
|
||||
#define _VERILATED_VCD_C_H_ 1
|
||||
|
||||
#include "verilatedos.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
class VerilatedVcd;
|
||||
class VerilatedVcdCallInfo;
|
||||
|
||||
// SPDIFF_ON
|
||||
//=============================================================================
|
||||
// VerilatedFile
|
||||
/// File handling routines, which can be overrode for e.g. socket I/O
|
||||
|
||||
class VerilatedVcdFile {
|
||||
private:
|
||||
int m_fd; ///< File descriptor we're writing to
|
||||
public:
|
||||
// METHODS
|
||||
VerilatedVcdFile() : m_fd(0) {}
|
||||
virtual ~VerilatedVcdFile() {}
|
||||
virtual bool open(const std::string& name);
|
||||
virtual void close();
|
||||
virtual ssize_t write(const char* bufp, ssize_t len);
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// 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 {
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
|
||||
std::vector<VerilatedVcdSig> m_sigs; ///< Pointer to signal information
|
||||
std::vector<VerilatedVcdCallInfo*> m_callbacks; ///< Routines to perform dumping
|
||||
typedef std::map<std::string,std::string> NameMap;
|
||||
NameMap* m_namemapp; ///< List of names for the header
|
||||
|
||||
typedef std::vector<VerilatedVcd*> VcdVec;
|
||||
struct Singleton {
|
||||
VcdVec s_vcdVecp; ///< List of all created traces
|
||||
};
|
||||
static Singleton& singleton() { static Singleton s; return s; }
|
||||
|
||||
void bufferResize(vluint64_t minsize);
|
||||
void bufferFlush();
|
||||
inline void bufferCheck() {
|
||||
// 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_writep > m_wrFlushp)) {
|
||||
bufferFlush();
|
||||
}
|
||||
}
|
||||
void closePrev();
|
||||
void closeErr();
|
||||
void openNext();
|
||||
void makeNameMap();
|
||||
void deleteNameMap();
|
||||
void printIndent (int levelchange);
|
||||
void printStr (const char* str);
|
||||
void printQuad (vluint64_t n);
|
||||
void printTime (vluint64_t timeui);
|
||||
void declare (vluint32_t code, const char* name, const char* wirep,
|
||||
int arraynum, 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) {
|
||||
if (code>=(94*94*94)) *m_writep++ = ((char)((code/94/94/94)%94+33));
|
||||
if (code>=(94*94)) *m_writep++ = ((char)((code/94/94)%94+33));
|
||||
if (code>=(94)) *m_writep++ = ((char)((code/94)%94+33));
|
||||
*m_writep++ = ((char)((code)%94+33));
|
||||
}
|
||||
static std::string stringCode (vluint32_t code) {
|
||||
std::string out;
|
||||
if (code>=(94*94*94)) out += ((char)((code/94/94/94)%94+33));
|
||||
if (code>=(94*94)) out += ((char)((code/94/94)%94+33));
|
||||
if (code>=(94)) out += ((char)((code/94)%94+33));
|
||||
return out + ((char)((code)%94+33));
|
||||
}
|
||||
|
||||
VerilatedVcd(const VerilatedVcd& ); ///< N/A, no copy constructor
|
||||
|
||||
protected:
|
||||
// METHODS
|
||||
void evcd(bool flag) { m_evcd = flag; }
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
explicit VerilatedVcd(VerilatedVcdFile* filep=NULL);
|
||||
~VerilatedVcd();
|
||||
|
||||
// ACCESSORS
|
||||
/// Inside dumping routines, return next VCD signal code
|
||||
vluint32_t nextCode() const {return m_nextCode;}
|
||||
/// 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); ///< Open the file; call isOpen() to see if errors
|
||||
void openNext (bool incFilename); ///< Open next data-only file
|
||||
void flush() { bufferFlush(); } ///< Flush any remaining data
|
||||
static void flush_all(); ///< Flush any remaining data from all files
|
||||
void close (); ///< Close the file
|
||||
|
||||
void set_time_unit (const char* unit); ///< Set time units (s/ms, defaults to ns)
|
||||
void set_time_unit (const std::string& unit) { set_time_unit(unit.c_str()); }
|
||||
|
||||
void set_time_resolution (const char* unit); ///< Set time resolution (s/ms, defaults to ns)
|
||||
void set_time_resolution (const std::string& unit) { set_time_resolution(unit.c_str()); }
|
||||
|
||||
double timescaleToDouble (const char* unitp);
|
||||
std::string doubleToTimescale (double value);
|
||||
|
||||
/// 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((vluint64_t)(secs * m_timeRes)); }
|
||||
|
||||
/// Inside dumping routines, declare callbacks for tracings
|
||||
void addCallback (VerilatedVcdCallback_t init, VerilatedVcdCallback_t full,
|
||||
VerilatedVcdCallback_t change,
|
||||
void* userthis);
|
||||
|
||||
/// 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, int arraynum);
|
||||
void declBus (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declQuad (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
void declArray (vluint32_t code, const char* name, int arraynum, int msb, int lsb);
|
||||
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 declDouble (vluint32_t code, const char* name, int arraynum);
|
||||
void declFloat (vluint32_t code, const char* name, int arraynum);
|
||||
// ... other module_start for submodules (based on cell name)
|
||||
|
||||
/// 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'+(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) {
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code])) = newval;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++=((newval&(1ULL<<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 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) {
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code])) = newval;
|
||||
(*((vluint64_t*)&m_sigs_oldvalp[code+1])) = newtri;
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
*m_writep++ = "01zz"[((newval >> bit)&1ULL)
|
||||
| (((newtri >> bit)&1ULL)<<1ULL)];
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullTriArray (vluint32_t code, const vluint32_t* newvalp, const vluint32_t* newtrip, int bits) {
|
||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
||||
m_sigs_oldvalp[code+word*2] = newvalp[word];
|
||||
m_sigs_oldvalp[code+word*2+1] = newtrip[word];
|
||||
}
|
||||
*m_writep++='b';
|
||||
for (int bit=bits-1; bit>=0; --bit) {
|
||||
vluint32_t valbit = (newvalp[(bit/32)]>>(bit&0x1f)) & 1;
|
||||
vluint32_t tribit = (newtrip[(bit/32)]>>(bit&0x1f)) & 1;
|
||||
*m_writep++ = "01zz"[valbit | (tribit<<1)];
|
||||
}
|
||||
*m_writep++=' '; printCode(code); *m_writep++='\n';
|
||||
bufferCheck();
|
||||
}
|
||||
void fullDouble (vluint32_t code, const double newval);
|
||||
void 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
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgBus (vluint32_t code, const vluint32_t newval, int bits) {
|
||||
vluint32_t diff = m_sigs_oldvalp[code] ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
if (VL_UNLIKELY(bits==32 || (diff & ((1U<<bits)-1) ))) {
|
||||
fullBus (code, newval, bits);
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgQuad (vluint32_t code, const vluint64_t newval, int bits) {
|
||||
vluint64_t diff = (*((vluint64_t*)&m_sigs_oldvalp[code])) ^ newval;
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
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) {
|
||||
for (int word=0; word<(((bits-1)/32)+1); ++word) {
|
||||
if (VL_UNLIKELY(m_sigs_oldvalp[code+word] ^ newval[word])) {
|
||||
fullArray (code,newval,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));
|
||||
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?
|
||||
fullTriBit (code, newval, newtri);
|
||||
}
|
||||
}
|
||||
}
|
||||
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));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
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 = ( ((*((vluint64_t*)&m_sigs_oldvalp[code])) ^ newval)
|
||||
| ((*((vluint64_t*)&m_sigs_oldvalp[code+1])) ^ newtri));
|
||||
if (VL_UNLIKELY(diff)) {
|
||||
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);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
inline void chgDouble (vluint32_t code, const double newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY((*((double*)&m_sigs_oldvalp[code])) != newval)) {
|
||||
fullDouble (code, newval);
|
||||
}
|
||||
}
|
||||
inline void chgFloat (vluint32_t code, const float newval) {
|
||||
// cppcheck-suppress invalidPointerCast
|
||||
if (VL_UNLIKELY((*((float*)&m_sigs_oldvalp[code])) != newval)) {
|
||||
fullFloat (code, newval);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
// VerilatedVcdC
|
||||
/// Create a VCD dump file in C standalone (no SystemC) simulations.
|
||||
|
||||
class VerilatedVcdC {
|
||||
VerilatedVcd m_sptrace; ///< Trace file being created
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
explicit VerilatedVcdC(VerilatedVcdFile* filep=NULL) : m_sptrace(filep) {}
|
||||
~VerilatedVcdC() {}
|
||||
// ACCESSORS
|
||||
/// Is file open?
|
||||
bool isOpen() const { return m_sptrace.isOpen(); }
|
||||
// METHODS
|
||||
/// Open a new VCD file
|
||||
/// This includes a complete header dump each time it is called,
|
||||
/// just as if this object was deleted and reconstructed.
|
||||
void open (const char* filename) { m_sptrace.open(filename); }
|
||||
/// Continue a VCD dump by rotating to a new file name
|
||||
/// The header is only in the first file created, this allows
|
||||
/// "cat" to be used to combine the header plus any number of data files.
|
||||
void openNext (bool incFilename=true) { m_sptrace.openNext(incFilename); }
|
||||
/// Set size in megabytes after which new file should be created
|
||||
void rolloverMB(size_t rolloverMB) { m_sptrace.rolloverMB(rolloverMB); };
|
||||
/// Close dump
|
||||
void close() { m_sptrace.close(); }
|
||||
/// Flush dump
|
||||
void flush() { m_sptrace.flush(); }
|
||||
/// Write one cycle of dump data
|
||||
void dump (vluint64_t timeui) { m_sptrace.dump(timeui); }
|
||||
/// Write one cycle of dump data - backward compatible and to reduce
|
||||
/// conversion warnings. It's better to use a vluint64_t time instead.
|
||||
void dump (double timestamp) { dump((vluint64_t)timestamp); }
|
||||
void dump (vluint32_t timestamp) { dump((vluint64_t)timestamp); }
|
||||
void dump (int timestamp) { dump((vluint64_t)timestamp); }
|
||||
/// Set time units (s/ms, defaults to ns)
|
||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
||||
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()); }
|
||||
/// Set time resolution (s/ms, defaults to ns)
|
||||
/// See also VL_TIME_PRECISION, and VL_TIME_MULTIPLIER in verilated.h
|
||||
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()); }
|
||||
|
||||
/// Internal class access
|
||||
inline VerilatedVcd* spTrace () { return &m_sptrace; };
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
@@ -0,0 +1,160 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator tracing in VCD Format
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#include "verilatedos.h"
|
||||
#include "verilated_vcd_sc.h"
|
||||
|
||||
// SPDIFF_ON
|
||||
//======================================================================
|
||||
//======================================================================
|
||||
|
||||
//--------------------------------------------------
|
||||
#if (SYSTEMC_VERSION>=20050714)
|
||||
// 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 **) {}
|
||||
|
||||
# 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 ) {}
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_logic )
|
||||
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_B( sc_dt::int64 )
|
||||
DECL_TRACE_METHOD_B( sc_dt::uint64 )
|
||||
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_unsigned )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
#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
|
||||
|
||||
#undef DECL_TRACE_METHOD_A
|
||||
#undef DECL_TRACE_METHOD_B
|
||||
|
||||
//********************************************************************
|
||||
@@ -0,0 +1,213 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//=============================================================================
|
||||
//
|
||||
// THIS MODULE IS PUBLICLY LICENSED
|
||||
//
|
||||
// Copyright 2001-2017 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.
|
||||
//
|
||||
// This is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
// for more details.
|
||||
//
|
||||
//=============================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator tracing in VCD format
|
||||
///
|
||||
//=============================================================================
|
||||
// SPDIFF_OFF
|
||||
|
||||
#ifndef _VERILATED_VCD_SC_H_
|
||||
#define _VERILATED_VCD_SC_H_ 1
|
||||
|
||||
#include "verilated_sc.h"
|
||||
#include "verilated_vcd_c.h"
|
||||
|
||||
// SPDIFF_ON
|
||||
//=============================================================================
|
||||
// VerilatedVcdSc
|
||||
///
|
||||
/// This class is passed to the SystemC simulation kernel, just like a
|
||||
/// documented SystemC trace format.
|
||||
|
||||
class VerilatedVcdSc
|
||||
: sc_trace_file
|
||||
, public VerilatedVcdC
|
||||
{
|
||||
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);
|
||||
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() {}
|
||||
/// 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:
|
||||
/// Fake outs for linker
|
||||
|
||||
#ifdef NC_SYSTEMC
|
||||
// Cadence Incisive has these as abstract functions so we must create them
|
||||
virtual void set_time_unit( int exponent10_seconds ) {} // deprecated
|
||||
#endif
|
||||
#if defined(NC_SYSTEMC) || (SYSTEMC_VERSION>=20111100)
|
||||
virtual void set_time_unit( double v, sc_time_unit tu ) {}
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
# 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) \
|
||||
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 **);
|
||||
|
||||
DECL_TRACE_METHOD_A( bool )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_logic )
|
||||
|
||||
DECL_TRACE_METHOD_B( unsigned char )
|
||||
DECL_TRACE_METHOD_B( unsigned short )
|
||||
DECL_TRACE_METHOD_B( unsigned int )
|
||||
DECL_TRACE_METHOD_B( unsigned long )
|
||||
#ifdef SYSTEMC_64BIT_PATCHES
|
||||
DECL_TRACE_METHOD_B( unsigned long long)
|
||||
#endif
|
||||
DECL_TRACE_METHOD_B( char )
|
||||
DECL_TRACE_METHOD_B( short )
|
||||
DECL_TRACE_METHOD_B( int )
|
||||
DECL_TRACE_METHOD_B( long )
|
||||
DECL_TRACE_METHOD_B( sc_dt::int64 )
|
||||
DECL_TRACE_METHOD_B( sc_dt::uint64 )
|
||||
|
||||
DECL_TRACE_METHOD_A( float )
|
||||
DECL_TRACE_METHOD_A( double )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_int_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_uint_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_signed )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_unsigned )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast )
|
||||
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
|
||||
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
|
||||
|
||||
//--------------------------------------------------
|
||||
# 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
|
||||
};
|
||||
|
||||
#endif // guard
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,498 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2009-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//=========================================================================
|
||||
///
|
||||
/// \file
|
||||
/// \brief Verilator: VPI implementation code
|
||||
///
|
||||
/// This file must be compiled and linked against all objects
|
||||
/// created from Verilator or called by Verilator that use the VPI.
|
||||
///
|
||||
/// Code available from: http://www.veripool.org/verilator
|
||||
///
|
||||
//=========================================================================
|
||||
|
||||
#ifndef _VERILATED_VPI_H_
|
||||
#define _VERILATED_VPI_H_ 1 ///< Header Guard
|
||||
|
||||
#include "verilated.h"
|
||||
#include "verilated_syms.h"
|
||||
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
//======================================================================
|
||||
// From IEEE 1800-2009 annex K
|
||||
|
||||
#include "vltstd/vpi_user.h"
|
||||
|
||||
//======================================================================
|
||||
// Internal constants
|
||||
|
||||
#define VL_DEBUG_IF_PLI VL_DEBUG_IF
|
||||
#define VL_VPI_LINE_SIZE 8192
|
||||
|
||||
//======================================================================
|
||||
// Internal macros
|
||||
|
||||
#define _VL_VPI_INTERNAL VerilatedVpi::error_info()->setMessage(vpiInternal)->setMessage
|
||||
#define _VL_VPI_SYSTEM VerilatedVpi::error_info()->setMessage(vpiSystem )->setMessage
|
||||
#define _VL_VPI_ERROR VerilatedVpi::error_info()->setMessage(vpiError )->setMessage
|
||||
#define _VL_VPI_WARNING VerilatedVpi::error_info()->setMessage(vpiWarning )->setMessage
|
||||
#define _VL_VPI_NOTICE VerilatedVpi::error_info()->setMessage(vpiNotice )->setMessage
|
||||
#define _VL_VPI_ERROR_RESET VerilatedVpi::error_info()->resetError
|
||||
|
||||
// Not supported yet
|
||||
#define _VL_VPI_UNIMP() \
|
||||
_VL_VPI_ERROR(__FILE__,__LINE__,Verilated::catName("Unsupported VPI function: ",VL_FUNC));
|
||||
|
||||
//======================================================================
|
||||
// Implementation
|
||||
|
||||
// Base VPI handled object
|
||||
class VerilatedVpio {
|
||||
// MEM MANGLEMENT
|
||||
static vluint8_t* s_freeHead;
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
VerilatedVpio() {}
|
||||
virtual ~VerilatedVpio() {}
|
||||
inline static void* operator new(size_t size) {
|
||||
// We new and delete tons of vpi structures, so keep them around
|
||||
// To simplify our free list, we use a size large enough for all derived types
|
||||
// We reserve word zero for the next pointer, as that's safer in case a
|
||||
// dangling reference to the original remains around.
|
||||
static size_t chunk = 96;
|
||||
if (VL_UNLIKELY(size>chunk)) vl_fatal(__FILE__,__LINE__,"", "increase chunk");
|
||||
if (VL_LIKELY(s_freeHead)) {
|
||||
vluint8_t* newp = s_freeHead;
|
||||
s_freeHead = *((vluint8_t**)newp);
|
||||
return newp+8;
|
||||
} else {
|
||||
// +8: 8 bytes for next
|
||||
vluint8_t* newp = (vluint8_t*)(::operator new(chunk+8));
|
||||
return newp+8;
|
||||
}
|
||||
}
|
||||
inline static void operator delete(void* obj, size_t size) {
|
||||
vluint8_t* oldp = ((vluint8_t*)obj)-8;
|
||||
*((void**)oldp) = s_freeHead;
|
||||
s_freeHead = oldp;
|
||||
}
|
||||
// MEMBERS
|
||||
static inline VerilatedVpio* castp(vpiHandle h) { return dynamic_cast<VerilatedVpio*>((VerilatedVpio*)h); }
|
||||
inline vpiHandle castVpiHandle() { return (vpiHandle)(this); }
|
||||
// ACCESSORS
|
||||
virtual const char* name() { return "<null>"; }
|
||||
virtual const char* fullname() { return "<null>"; }
|
||||
virtual const char* defname() { return "<null>"; }
|
||||
virtual vluint32_t type() { return 0; }
|
||||
virtual vluint32_t size() const { return 0; }
|
||||
virtual const VerilatedRange* rangep() const { return NULL; }
|
||||
virtual vpiHandle dovpi_scan() { return 0; }
|
||||
};
|
||||
|
||||
typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data *);
|
||||
|
||||
class VerilatedVpioCb : public VerilatedVpio {
|
||||
t_cb_data m_cbData;
|
||||
s_vpi_value m_value;
|
||||
QData m_time;
|
||||
public:
|
||||
// cppcheck-suppress uninitVar // m_value
|
||||
VerilatedVpioCb(const t_cb_data* cbDatap, QData time)
|
||||
: m_cbData(*cbDatap), m_time(time) {
|
||||
m_value.format = cbDatap->value ? cbDatap->value->format : vpiSuppressVal;
|
||||
m_cbData.value = &m_value;
|
||||
}
|
||||
virtual ~VerilatedVpioCb() {}
|
||||
static inline VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioCb*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiCallback; }
|
||||
vluint32_t reason() const { return m_cbData.reason; }
|
||||
VerilatedPliCb cb_rtnp() const { return m_cbData.cb_rtn; }
|
||||
t_cb_data* cb_datap() { return &(m_cbData); }
|
||||
QData time() const { return m_time; }
|
||||
};
|
||||
|
||||
class VerilatedVpioConst : public VerilatedVpio {
|
||||
vlsint32_t m_num;
|
||||
public:
|
||||
explicit VerilatedVpioConst(vlsint32_t num) : m_num(num) {}
|
||||
virtual ~VerilatedVpioConst() {}
|
||||
static inline VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioConst*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiUndefined; }
|
||||
vlsint32_t num() const { return m_num; }
|
||||
};
|
||||
|
||||
class VerilatedVpioRange : public VerilatedVpio {
|
||||
const VerilatedRange* m_range;
|
||||
vlsint32_t m_iteration;
|
||||
public:
|
||||
explicit VerilatedVpioRange(const VerilatedRange* range) : m_range(range), m_iteration(0) {}
|
||||
virtual ~VerilatedVpioRange() {}
|
||||
static inline VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioRange*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiRange; }
|
||||
virtual vluint32_t size() const { return m_range->elements(); }
|
||||
virtual const VerilatedRange* rangep() const { return m_range; }
|
||||
int iteration() const { return m_iteration; }
|
||||
void iterationInc() { ++m_iteration; }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
if (!iteration()) {
|
||||
VerilatedVpioRange* nextp = new VerilatedVpioRange(*this);
|
||||
nextp->iterationInc();
|
||||
return ((nextp)->castVpiHandle());
|
||||
} else {
|
||||
return 0; // End of list - only one deep
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioScope : public VerilatedVpio {
|
||||
const VerilatedScope* m_scopep;
|
||||
public:
|
||||
explicit VerilatedVpioScope(const VerilatedScope* scopep)
|
||||
: m_scopep(scopep) {}
|
||||
virtual ~VerilatedVpioScope() {}
|
||||
static inline VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioScope*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiScope; }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
virtual const char* name() { return m_scopep->name(); }
|
||||
virtual const char* fullname() { return m_scopep->name(); }
|
||||
};
|
||||
|
||||
class VerilatedVpioVar : public VerilatedVpio {
|
||||
const VerilatedVar* m_varp;
|
||||
const VerilatedScope* m_scopep;
|
||||
vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange
|
||||
union {
|
||||
vluint8_t u8[4];
|
||||
vluint32_t u32;
|
||||
} m_mask; // memoized variable mask
|
||||
vluint32_t m_entSize; // memoized variable size
|
||||
protected:
|
||||
void* m_varDatap; // varp()->datap() adjusted for array entries
|
||||
vlsint32_t m_index;
|
||||
const VerilatedRange& get_range() const {
|
||||
// Determine number of dimensions and return outermost
|
||||
return (m_varp->dims()>1) ? m_varp->array() : m_varp->range();
|
||||
}
|
||||
public:
|
||||
VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep)
|
||||
: m_varp(varp), m_scopep(scopep), m_index(0) {
|
||||
m_prevDatap = NULL;
|
||||
m_mask.u32 = VL_MASK_I(varp->range().elements());
|
||||
m_entSize = varp->entSize();
|
||||
m_varDatap = varp->datap();
|
||||
}
|
||||
virtual ~VerilatedVpioVar() {
|
||||
if (m_prevDatap) { delete [] m_prevDatap; m_prevDatap = NULL; }
|
||||
}
|
||||
static inline VerilatedVpioVar* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVar*>((VerilatedVpio*)h); }
|
||||
const VerilatedVar* varp() const { return m_varp; }
|
||||
const VerilatedScope* scopep() const { return m_scopep; }
|
||||
vluint32_t mask() const { return m_mask.u32; }
|
||||
vluint8_t mask_byte(int idx) { return m_mask.u8[idx & 3]; }
|
||||
vluint32_t entSize() const { return m_entSize; }
|
||||
vluint32_t index() { return m_index; }
|
||||
virtual vluint32_t type() {
|
||||
if (varp()->vldir() != vpiNoDirection) return vpiPort;
|
||||
return (varp()->dims()>1) ? vpiMemory : vpiReg; /* but might be wire, logic */
|
||||
}
|
||||
virtual vluint32_t size() const { return get_range().elements(); }
|
||||
virtual const VerilatedRange* rangep() const { return &get_range(); }
|
||||
virtual const char* name() { return m_varp->name(); }
|
||||
virtual const char* fullname() {
|
||||
VL_STATIC_OR_THREAD std::string out;
|
||||
out = std::string(m_scopep->name())+"."+name();
|
||||
return out.c_str();
|
||||
}
|
||||
void* prevDatap() const { return m_prevDatap; }
|
||||
void* varDatap() const { return m_varDatap; }
|
||||
void createPrevDatap() {
|
||||
if (VL_UNLIKELY(!m_prevDatap)) {
|
||||
m_prevDatap = new vluint8_t [entSize()];
|
||||
memcpy(prevDatap(), varp()->datap(), entSize());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioMemoryWord : public VerilatedVpioVar {
|
||||
public:
|
||||
VerilatedVpioMemoryWord(const VerilatedVar* varp, const VerilatedScope* scopep,
|
||||
vlsint32_t index, int offset)
|
||||
: VerilatedVpioVar(varp, scopep) {
|
||||
m_index = index;
|
||||
m_varDatap = ((vluint8_t*)varp->datap()) + entSize()*offset;
|
||||
}
|
||||
virtual ~VerilatedVpioMemoryWord() {}
|
||||
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWord*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiMemoryWord; }
|
||||
virtual vluint32_t size() const { return varp()->range().elements(); }
|
||||
virtual const VerilatedRange* rangep() const { return &(varp()->range()); }
|
||||
virtual const char* fullname() {
|
||||
VL_STATIC_OR_THREAD std::string out;
|
||||
char num[20]; sprintf(num,"%d",m_index);
|
||||
out = std::string(scopep()->name())+"."+name()+"["+num+"]";
|
||||
return out.c_str();
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioVarIter : public VerilatedVpio {
|
||||
const VerilatedScope* m_scopep;
|
||||
VerilatedVarNameMap::iterator m_it;
|
||||
bool m_started;
|
||||
public:
|
||||
explicit VerilatedVpioVarIter(const VerilatedScope* scopep)
|
||||
: m_scopep(scopep), m_started(false) { }
|
||||
virtual ~VerilatedVpioVarIter() {}
|
||||
static inline VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioVarIter*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiIterator; }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
if (VL_LIKELY(m_scopep->varsp())) {
|
||||
VerilatedVarNameMap* varsp = m_scopep->varsp();
|
||||
if (VL_UNLIKELY(!m_started)) { m_it = varsp->begin(); m_started=true; }
|
||||
else if (VL_UNLIKELY(m_it == varsp->end())) return 0;
|
||||
else ++m_it;
|
||||
if (m_it == varsp->end()) return 0;
|
||||
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))
|
||||
->castVpiHandle());
|
||||
} else {
|
||||
return 0; // End of list - only one deep
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpioMemoryWordIter : public VerilatedVpio {
|
||||
const vpiHandle m_handle;
|
||||
const VerilatedVar* m_varp;
|
||||
vlsint32_t m_iteration;
|
||||
vlsint32_t m_direction;
|
||||
bool m_done;
|
||||
public:
|
||||
VerilatedVpioMemoryWordIter(const vpiHandle handle, const VerilatedVar* varp)
|
||||
: m_handle(handle), m_varp(varp), m_iteration(varp->array().right()), m_direction(VL_LIKELY(varp->array().left()>varp->array().right())?1:-1), m_done(false) { }
|
||||
virtual ~VerilatedVpioMemoryWordIter() {}
|
||||
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWordIter*>((VerilatedVpio*)h); }
|
||||
virtual vluint32_t type() { return vpiIterator; }
|
||||
void iterationInc() { if (!(m_done = (m_iteration == m_varp->array().left()))) m_iteration+=m_direction; }
|
||||
virtual vpiHandle dovpi_scan() {
|
||||
vpiHandle result;
|
||||
if (m_done) return 0;
|
||||
result = vpi_handle_by_index(m_handle, m_iteration);
|
||||
iterationInc();
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
struct VerilatedVpiTimedCbsCmp {
|
||||
/// Ordering sets keyed by time, then callback descriptor
|
||||
bool operator() (const std::pair<QData,VerilatedVpioCb*>& a,
|
||||
const std::pair<QData,VerilatedVpioCb*>& b) const {
|
||||
if (a.first < b.first) return 1;
|
||||
if (a.first > b.first) return 0;
|
||||
return a.second < b.second;
|
||||
}
|
||||
};
|
||||
|
||||
class VerilatedVpiError;
|
||||
|
||||
class VerilatedVpi {
|
||||
enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime+1 }; // Maxium callback reason
|
||||
typedef std::list<VerilatedVpioCb*> VpioCbList;
|
||||
typedef std::set<std::pair<QData,VerilatedVpioCb*>,VerilatedVpiTimedCbsCmp > VpioTimedCbs;
|
||||
|
||||
struct product_info {
|
||||
PLI_BYTE8* product;
|
||||
};
|
||||
|
||||
VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason
|
||||
VpioTimedCbs m_timedCbs; // Time based callbacks
|
||||
VerilatedVpiError* m_errorInfop; // Container for vpi error info
|
||||
|
||||
static VerilatedVpi s_s; // Singleton
|
||||
|
||||
public:
|
||||
VerilatedVpi() { m_errorInfop=NULL; }
|
||||
~VerilatedVpi() {}
|
||||
static void cbReasonAdd(VerilatedVpioCb* vop) {
|
||||
if (vop->reason() == cbValueChange) {
|
||||
if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) {
|
||||
varop->createPrevDatap();
|
||||
}
|
||||
}
|
||||
if (VL_UNLIKELY(vop->reason() >= CB_ENUM_MAX_VALUE)) vl_fatal(__FILE__,__LINE__,"", "vpi bb reason too large");
|
||||
s_s.m_cbObjLists[vop->reason()].push_back(vop);
|
||||
}
|
||||
static void cbTimedAdd(VerilatedVpioCb* vop) {
|
||||
s_s.m_timedCbs.insert(std::make_pair(vop->time(), vop));
|
||||
}
|
||||
static void cbReasonRemove(VerilatedVpioCb* cbp) {
|
||||
VpioCbList& cbObjList = s_s.m_cbObjLists[cbp->reason()];
|
||||
// We do not remove it now as we may be iterating the list,
|
||||
// instead set to NULL and will cleanup later
|
||||
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end(); ++it) {
|
||||
if (*it == cbp) *it = NULL;
|
||||
}
|
||||
}
|
||||
static void cbTimedRemove(VerilatedVpioCb* cbp) {
|
||||
VpioTimedCbs::iterator it=s_s.m_timedCbs.find(std::make_pair(cbp->time(),cbp));
|
||||
if (VL_LIKELY(it != s_s.m_timedCbs.end())) {
|
||||
s_s.m_timedCbs.erase(it);
|
||||
}
|
||||
}
|
||||
static void callTimedCbs() {
|
||||
QData time = VL_TIME_Q();
|
||||
for (VpioTimedCbs::iterator it=s_s.m_timedCbs.begin(); it!=s_s.m_timedCbs.end(); ) {
|
||||
if (VL_UNLIKELY(it->first <= time)) {
|
||||
VerilatedVpioCb* vop = it->second;
|
||||
++it; // iterator may be deleted by callback
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: timed_callback %p\n",vop););
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
else { ++it; }
|
||||
}
|
||||
}
|
||||
static QData cbNextDeadline() {
|
||||
VpioTimedCbs::iterator it=s_s.m_timedCbs.begin();
|
||||
if (VL_LIKELY(it!=s_s.m_timedCbs.end())) {
|
||||
return it->first;
|
||||
} else {
|
||||
return ~VL_ULL(0); // maxquad
|
||||
}
|
||||
}
|
||||
static void callCbs(vluint32_t reason) {
|
||||
VpioCbList& cbObjList = s_s.m_cbObjLists[reason];
|
||||
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) {
|
||||
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
|
||||
it = cbObjList.erase(it);
|
||||
continue;
|
||||
}
|
||||
VerilatedVpioCb* vop = *it++;
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: reason_callback %d %p\n",reason,vop););
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
}
|
||||
static void callValueCbs() {
|
||||
VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange];
|
||||
typedef std::set<VerilatedVpioVar*> VpioVarSet;
|
||||
VpioVarSet update; // set of objects to update after callbacks
|
||||
for (VpioCbList::iterator it=cbObjList.begin(); it!=cbObjList.end();) {
|
||||
if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup
|
||||
it = cbObjList.erase(it);
|
||||
continue;
|
||||
}
|
||||
VerilatedVpioCb* vop = *it++;
|
||||
if (VerilatedVpioVar* varop = VerilatedVpioVar::castp(vop->cb_datap()->obj)) {
|
||||
void* newDatap = varop->varDatap();
|
||||
void* prevDatap = varop->prevDatap(); // Was malloced when we added the callback
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_test %s v[0]=%d/%d %p %p\n",
|
||||
varop->fullname(), *((CData*)newDatap), *((CData*)prevDatap),
|
||||
newDatap, prevDatap););
|
||||
if (memcmp(prevDatap, newDatap, varop->entSize())) {
|
||||
VL_DEBUG_IF_PLI(VL_PRINTF("-vltVpi: value_callback %p %s v[0]=%d\n",
|
||||
vop,varop->fullname(), *((CData*)newDatap)););
|
||||
update.insert(varop);
|
||||
vpi_get_value(vop->cb_datap()->obj, vop->cb_datap()->value);
|
||||
(vop->cb_rtnp()) (vop->cb_datap());
|
||||
}
|
||||
}
|
||||
}
|
||||
for (VpioVarSet::iterator it=update.begin(); it!=update.end(); ++it) {
|
||||
memcpy((*it)->prevDatap(), (*it)->varDatap(), (*it)->entSize());
|
||||
}
|
||||
}
|
||||
|
||||
static VerilatedVpiError* error_info(); // getter for vpi error info
|
||||
};
|
||||
|
||||
#define _VL_VPI_ERROR_SET \
|
||||
do { \
|
||||
va_list args; \
|
||||
va_start(args, message); \
|
||||
VL_VSNPRINTF(m_buff, sizeof(m_buff), message.c_str(), args); \
|
||||
va_end(args); \
|
||||
} while (0)
|
||||
|
||||
class VerilatedVpiError {
|
||||
//// Container for vpi error info
|
||||
|
||||
t_vpi_error_info m_errorInfo;
|
||||
bool m_flag;
|
||||
char m_buff[VL_VPI_LINE_SIZE];
|
||||
void setError(PLI_BYTE8 *message, PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line) {
|
||||
m_errorInfo.message = message;
|
||||
m_errorInfo.file = file;
|
||||
m_errorInfo.line = line;
|
||||
m_errorInfo.code = code;
|
||||
do_callbacks();
|
||||
}
|
||||
void do_callbacks() {
|
||||
if (getError()->level >= vpiError && Verilated::fatalOnVpiError()) {
|
||||
// Stop on vpi error/unsupported
|
||||
vpi_unsupported();
|
||||
}
|
||||
// We need to run above code first because in the case that the callback executes further vpi
|
||||
// functions we will loose the error as it will be overwritten.
|
||||
VerilatedVpi::callCbs(cbPLIError);
|
||||
}
|
||||
public:
|
||||
|
||||
VerilatedVpiError() : m_flag(false) {
|
||||
m_buff[0] = '\0';
|
||||
m_errorInfo.product = (PLI_BYTE8*)Verilated::productName();
|
||||
}
|
||||
~VerilatedVpiError() {}
|
||||
static void selfTest();
|
||||
VerilatedVpiError* setMessage(PLI_INT32 level) {
|
||||
m_flag=true;
|
||||
m_errorInfo.level = level;
|
||||
return this;
|
||||
}
|
||||
void setMessage(std::string file, PLI_INT32 line, std::string message, ...) {
|
||||
static VL_THREAD std::string filehold;
|
||||
_VL_VPI_ERROR_SET;
|
||||
m_errorInfo.state = vpiPLI;
|
||||
filehold = file;
|
||||
setError((PLI_BYTE8*)m_buff, NULL, (PLI_BYTE8*)filehold.c_str(), line);
|
||||
}
|
||||
p_vpi_error_info getError() {
|
||||
if (m_flag) return &m_errorInfo;
|
||||
return NULL;
|
||||
}
|
||||
void resetError() {
|
||||
m_flag=false;
|
||||
}
|
||||
static void vpi_unsupported() {
|
||||
// Not supported yet
|
||||
p_vpi_error_info error_info_p = VerilatedVpi::error_info()->getError();
|
||||
if (error_info_p) {
|
||||
vl_fatal(error_info_p->file, error_info_p->line, "", error_info_p->message);
|
||||
return;
|
||||
}
|
||||
vl_fatal(__FILE__, __LINE__, "", "vpi_unsupported called without error info set");
|
||||
}
|
||||
static const char* strFromVpiVal(PLI_INT32 vpiVal);
|
||||
static const char* strFromVpiObjType(PLI_INT32 vpiVal);
|
||||
static const char* strFromVpiMethod(PLI_INT32 vpiVal);
|
||||
static const char* strFromVpiCallbackReason(PLI_INT32 vpiVal);
|
||||
static const char* strFromVpiProp(PLI_INT32 vpiVal);
|
||||
};
|
||||
|
||||
//======================================================================
|
||||
|
||||
#endif // Guard
|
||||
+158
-17
@@ -1,7 +1,7 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -34,21 +34,43 @@
|
||||
// Compiler pragma abstraction
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, fmtArgNum, fmtArgNum+1)))
|
||||
# define VL_ATTR_ALIGNED(alignment) __attribute__ ((aligned (alignment)))
|
||||
# define VL_ATTR_ALWINLINE __attribute__ ((always_inline))
|
||||
# define VL_ATTR_NORETURN __attribute__ ((noreturn))
|
||||
# ifdef _WIN32
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) // GCC with MS runtime will fool the print arg checker
|
||||
# else
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) __attribute__ ((format (printf, fmtArgNum, fmtArgNum+1)))
|
||||
# endif
|
||||
# define VL_ATTR_UNUSED __attribute__ ((unused))
|
||||
# define VL_FUNC __func__
|
||||
# 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)
|
||||
#elif defined(_MSC_VER)
|
||||
# define VL_ATTR_ALIGNED(alignment)
|
||||
# define VL_ATTR_ALWINLINE
|
||||
# define VL_ATTR_NORETURN
|
||||
# define VL_ATTR_PRINTF(fmtArgNum)
|
||||
# define VL_ATTR_UNUSED
|
||||
# define VL_FUNC __FUNCTION__
|
||||
# define VL_LIKELY(x) (!!(x))
|
||||
# define VL_UNLIKELY(x) (!!(x))
|
||||
# define VL_UNREACHABLE
|
||||
# define VL_PREFETCH_RD(p)
|
||||
# define VL_PREFETCH_RW(p)
|
||||
#else
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
# define VL_ATTR_ALIGNED(alignment) ///< Align structure to specified byte alignment
|
||||
# define VL_ATTR_ALWINLINE ///< Inline, even when not optimizing
|
||||
# define VL_ATTR_NORETURN ///< Function does not ever return
|
||||
# define VL_ATTR_PRINTF(fmtArgNum) ///< Function with printf format checking
|
||||
# define VL_ATTR_UNUSED ///< Function that may be never used
|
||||
# define VL_FUNC "__func__" ///< Name of current function for error macros
|
||||
# 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_UNREACHABLE ///< Point that may never be reached
|
||||
# define VL_PREFETCH_RD(p) ///< Prefetch data with read intent
|
||||
# define VL_PREFETCH_RW(p) ///< Prefetch data with read/write intent
|
||||
#endif
|
||||
@@ -59,8 +81,12 @@
|
||||
# else
|
||||
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
|
||||
# endif
|
||||
# define VL_STATIC_OR_THREAD ///< Static if unthreaded, as some strings can be faster
|
||||
// ///< if non-dynamic and can't do "static VL_THREAD string"
|
||||
#else
|
||||
# define VL_THREAD ///< Storage class for thread-local storage
|
||||
# define VL_STATIC_OR_THREAD static ///< Static if unthreaded, as some strings can be faster
|
||||
// ///< if non-dynamic and can't do "static VL_THREAD string"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
@@ -72,40 +98,143 @@
|
||||
// This is not necessarily the same as #UL, depending on what the IData typedef is.
|
||||
#define VL_UL(c) ((IData)(c##UL)) ///< Add appropriate suffix to 32-bit constant
|
||||
|
||||
#if defined(VL_CPPCHECK) || defined(__clang_analyzer__)
|
||||
# define VL_DANGLING(v)
|
||||
#else
|
||||
# define VL_DANGLING(v) do { (v) = NULL; } while(0) ///< After e.g. delete, set variable to NULL to indicate must not use later
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// C++-2011
|
||||
|
||||
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
|
||||
# define VL_HAS_UNIQUE_PTR
|
||||
# define VL_UNIQUE_PTR unique_ptr
|
||||
#else
|
||||
# define VL_UNIQUE_PTR auto_ptr
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Optimization
|
||||
|
||||
#ifndef VL_INLINE_OPT
|
||||
# define VL_INLINE_OPT ///< "inline" if compiling all objects in single compiler run
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Warning disabled
|
||||
|
||||
#ifndef VL_WARNINGS
|
||||
# ifdef _MSC_VER
|
||||
# pragma warning(disable:4099) // C4099: type name first seen using 'class' now seen using 'struct' (V3AstNode)
|
||||
# pragma warning(disable:4100) // C4100: unreferenced formal parameter (L4)
|
||||
# pragma warning(disable:4127) // C4127: conditional expression is constant (L4)
|
||||
# pragma warning(disable:4146) // C4146: unary minus operator applied to unsigned type, result still unsigned
|
||||
# pragma warning(disable:4189) // C4189: local variable is initialized but not referenced (L4)
|
||||
# pragma warning(disable:4244) // C4244: conversion from 'uint64_t' to 'uint_32_t', possible loss of data
|
||||
# pragma warning(disable:4245) // C4245: conversion from 'int' to 'unsigned', signed/unsigned mismatch
|
||||
# pragma warning(disable:4996) // C4996: sscanf/fopen/etc may be unsafe
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Basic integer types
|
||||
|
||||
#ifdef VL_UINTS_DEFINED
|
||||
#elif defined(__CYGWIN__)
|
||||
|
||||
# include <stdint.h>
|
||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned long uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||
typedef long vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned long vluint32_t; ///< 32-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
|
||||
# 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
|
||||
# endif
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
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 unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
# endif
|
||||
|
||||
#elif defined(_WIN32) && defined(_MSC_VER)
|
||||
typedef unsigned char uint8_t; ///< 8-bit unsigned type (backward compatibility)
|
||||
typedef unsigned short int uint16_t; ///< 16-bit unsigned type (backward compatibility)
|
||||
typedef unsigned int uint32_t; ///< 32-bit unsigned type (backward compatibility)
|
||||
typedef unsigned char vluint8_t; ///< 8-bit unsigned type
|
||||
typedef unsigned short int vluint16_t; ///< 16-bit unsigned type
|
||||
typedef int vlsint32_t; ///< 32-bit signed type
|
||||
typedef unsigned int vluint32_t; ///< 32-bit unsigned type
|
||||
typedef __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 unsigned __int8 vluint8_t; ///< 8-bit unsigned 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()
|
||||
# else
|
||||
typedef signed __int32 ssize_t; ///< signed size_t; returned from read()
|
||||
# endif
|
||||
# endif
|
||||
|
||||
#else // Linux or compliant Unix flavors, -m64
|
||||
|
||||
# include <stdint.h> // Linux and most flavors
|
||||
# include <unistd.h> // Linux ssize_t
|
||||
# include <inttypes.h> // Solaris
|
||||
typedef uint8_t vluint8_t; ///< 32-bit unsigned type
|
||||
typedef uint16_t vluint16_t; ///< 32-bit unsigned type
|
||||
typedef int vlsint32_t; ///< 32-bit signed type
|
||||
typedef uint32_t vluint32_t; ///< 32-bit signed type
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
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
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// Printing printf/scanf formats
|
||||
// Alas cinttypes isn't that standard yet
|
||||
|
||||
#ifdef _WIN32
|
||||
# define VL_PRI64 "I64"
|
||||
#else // Linux or compliant Unix flavors
|
||||
# if defined(__WORDSIZE) && (__WORDSIZE == 64)
|
||||
# define VL_PRI64 "l"
|
||||
# else
|
||||
# define VL_PRI64 "ll"
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(_WIN32) && defined(_MSC_VER)
|
||||
# if (_MSC_VER < 1900)
|
||||
# define VL_SNPRINTF _snprintf
|
||||
# else
|
||||
# define VL_SNPRINTF snprintf
|
||||
# endif
|
||||
# define VL_VSNPRINTF vsnprintf
|
||||
#else
|
||||
# define VL_SNPRINTF snprintf
|
||||
# define VL_VSNPRINTF vsnprintf
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
// File system functions
|
||||
|
||||
#ifdef _WIN32
|
||||
# define VL_DEV_NULL "nul"
|
||||
#else // Linux or compliant Unix flavors
|
||||
# define VL_DEV_NULL "/dev/null"
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
@@ -144,6 +273,18 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type
|
||||
#define VL_BITBIT_I(bit) ((bit)&VL_SIZEBITS_I) ///< Bit number for a bit in a long
|
||||
#define VL_BITBIT_Q(bit) ((bit)&VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
|
||||
|
||||
//=========================================================================
|
||||
// Floating point
|
||||
// #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))
|
||||
#else
|
||||
# define VL_TRUNC(n) trunc(n)
|
||||
# define VL_ROUND(n) round(n)
|
||||
#endif
|
||||
|
||||
//=========================================================================
|
||||
|
||||
#endif /*guard*/
|
||||
|
||||
@@ -0,0 +1,495 @@
|
||||
/* -*- C -*-
|
||||
*
|
||||
* svdpi.h
|
||||
*
|
||||
* SystemVerilog Direct Programming Interface (DPI).
|
||||
*
|
||||
* This file contains the constant definitions, structure definitions,
|
||||
* and routine declarations used by SystemVerilog DPI.
|
||||
*
|
||||
* This file is from the SystemVerilog IEEE 1800-2012 Annex I.
|
||||
*/
|
||||
|
||||
#ifndef INCLUDED_SVDPI
|
||||
#define INCLUDED_SVDPI
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Define size-critical types on all OS platforms. */
|
||||
#if defined (_MSC_VER)
|
||||
typedef unsigned __int64 uint64_t;
|
||||
typedef unsigned __int32 uint32_t;
|
||||
typedef unsigned __int8 uint8_t;
|
||||
typedef signed __int64 int64_t;
|
||||
typedef signed __int32 int32_t;
|
||||
typedef signed __int8 int8_t;
|
||||
#elif defined(__MINGW32__)
|
||||
#include <stdint.h>
|
||||
#elif defined(__APPLE__)
|
||||
#include <stdint.h>
|
||||
#elif defined(__linux) || (defined(__APPLE__) && defined(__MACH__))
|
||||
#include <inttypes.h>
|
||||
#else
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
/* Use to import a symbol into dll */
|
||||
#ifndef DPI_DLLISPEC
|
||||
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
|
||||
#define DPI_DLLISPEC __declspec(dllimport)
|
||||
#else
|
||||
#define DPI_DLLISPEC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Use to export a symbol from dll */
|
||||
#ifndef DPI_DLLESPEC
|
||||
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
|
||||
#define DPI_DLLESPEC __declspec(dllexport)
|
||||
#else
|
||||
#define DPI_DLLESPEC
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Use to mark a function as external */
|
||||
#ifndef DPI_EXTERN
|
||||
#define DPI_EXTERN
|
||||
#endif
|
||||
|
||||
#ifndef DPI_PROTOTYPES
|
||||
#define DPI_PROTOTYPES
|
||||
/* object is defined imported by the application */
|
||||
#define XXTERN DPI_EXTERN DPI_DLLISPEC
|
||||
/* object is exported by the application */
|
||||
#define EETERN DPI_EXTERN DPI_DLLESPEC
|
||||
#endif
|
||||
|
||||
/* canonical representation */
|
||||
#define sv_0 0
|
||||
#define sv_1 1
|
||||
#define sv_z 2
|
||||
#define sv_x 3
|
||||
|
||||
/* common type for 'bit' and 'logic' scalars. */
|
||||
typedef uint8_t svScalar;
|
||||
typedef svScalar svBit; /* scalar */
|
||||
typedef svScalar svLogic; /* scalar */
|
||||
|
||||
/*
|
||||
* DPI representation of packed arrays.
|
||||
* 2-state and 4-state vectors, exactly the same as PLI's avalue/bvalue.
|
||||
*/
|
||||
#ifndef VPI_VECVAL
|
||||
#define VPI_VECVAL
|
||||
typedef struct t_vpi_vecval {
|
||||
uint32_t aval;
|
||||
uint32_t bval;
|
||||
} s_vpi_vecval, *p_vpi_vecval;
|
||||
#endif
|
||||
|
||||
/* (a chunk of) packed logic array */
|
||||
typedef s_vpi_vecval svLogicVecVal;
|
||||
|
||||
/* (a chunk of) packed bit array */
|
||||
typedef uint32_t svBitVecVal;
|
||||
|
||||
/* Number of chunks required to represent the given width packed array */
|
||||
#define SV_PACKED_DATA_NELEMS(WIDTH) (((WIDTH) + 31) >> 5)
|
||||
|
||||
/*
|
||||
* Because the contents of the unused bits is undetermined,
|
||||
* the following macros can be handy.
|
||||
*/
|
||||
#define SV_MASK(N) (~(-1 << (N)))
|
||||
|
||||
#define SV_GET_UNSIGNED_BITS(VALUE, N) \
|
||||
((N) == 32 ? (VALUE) : ((VALUE) & SV_MASK(N)))
|
||||
|
||||
#define SV_GET_SIGNED_BITS(VALUE, N) \
|
||||
((N) == 32 ? (VALUE) : \
|
||||
(((VALUE) & (1 << (N))) ? ((VALUE) | ~SV_MASK(N)) : ((VALUE) & SV_MASK(N))))
|
||||
|
||||
/*
|
||||
* Implementation-dependent representation.
|
||||
*/
|
||||
/*
|
||||
* Return implementation version information string ("1800-2005" or "SV3.1a").
|
||||
*/
|
||||
XXTERN const char* svDpiVersion();
|
||||
|
||||
/* a handle to a scope (an instance of a module or interface) */
|
||||
XXTERN typedef void* svScope;
|
||||
|
||||
/* a handle to a generic object (actually, unsized array) */
|
||||
XXTERN typedef void* svOpenArrayHandle;
|
||||
|
||||
/*
|
||||
* Bit-select utility functions.
|
||||
*
|
||||
* Packed arrays are assumed to be indexed n-1:0,
|
||||
* where 0 is the index of LSB
|
||||
*/
|
||||
|
||||
/* s=source, i=bit-index */
|
||||
XXTERN svBit svGetBitselBit(const svBitVecVal* s, int i);
|
||||
XXTERN svLogic svGetBitselLogic(const svLogicVecVal* s, int i);
|
||||
|
||||
/* d=destination, i=bit-index, s=scalar */
|
||||
XXTERN void svPutBitselBit(svBitVecVal* d, int i, svBit s);
|
||||
XXTERN void svPutBitselLogic(svLogicVecVal* d, int i, svLogic s);
|
||||
|
||||
/*
|
||||
* Part-select utility functions.
|
||||
*
|
||||
* A narrow (<=32 bits) part-select is extracted from the
|
||||
* source representation and written into the destination word.
|
||||
*
|
||||
* Normalized ranges and indexing [n-1:0] are used for both arrays.
|
||||
*
|
||||
* s=source, d=destination, i=starting bit index, w=width
|
||||
* like for variable part-selects; limitations: w <= 32
|
||||
*/
|
||||
XXTERN void svGetPartselBit(svBitVecVal* d, const svBitVecVal* s, int i, int w);
|
||||
XXTERN void svGetPartselLogic(svLogicVecVal* d, const svLogicVecVal* s, int i, int w);
|
||||
|
||||
XXTERN void svPutPartselBit(svBitVecVal* d, const svBitVecVal s, int i, int w);
|
||||
XXTERN void svPutPartselLogic(svLogicVecVal* d, const svLogicVecVal* s, int i, int w);
|
||||
|
||||
/*
|
||||
* Open array querying functions
|
||||
* These functions are modeled upon the SystemVerilog array
|
||||
* querying functions and use the same semantics.
|
||||
*
|
||||
* If the dimension is 0, then the query refers to the
|
||||
* packed part of an array (which is one-dimensional).
|
||||
* Dimensions > 0 refer to the unpacked part of an array.
|
||||
*/
|
||||
/* h= handle to open array, d=dimension */
|
||||
XXTERN int svLeft(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svRight(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svLow(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svHigh(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svIncrement(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svSize(const svOpenArrayHandle h, int d);
|
||||
XXTERN int svDimensions(const svOpenArrayHandle h);
|
||||
|
||||
/*
|
||||
* Pointer to the actual representation of the whole array of any type
|
||||
* NULL if not in C layout
|
||||
*/
|
||||
XXTERN void *svGetArrayPtr(const svOpenArrayHandle);
|
||||
|
||||
/* total size in bytes or 0 if not in C layout */
|
||||
XXTERN int svSizeOfArray(const svOpenArrayHandle);
|
||||
|
||||
/*
|
||||
* Return a pointer to an element of the array
|
||||
* or NULL if index outside the range or null pointer
|
||||
*/
|
||||
XXTERN void *svGetArrElemPtr(const svOpenArrayHandle, int indx1, ...);
|
||||
|
||||
/* specialized versions for 1-, 2- and 3-dimensional arrays: */
|
||||
XXTERN void *svGetArrElemPtr1(const svOpenArrayHandle, int indx1);
|
||||
XXTERN void *svGetArrElemPtr2(const svOpenArrayHandle, int indx1, int indx2);
|
||||
XXTERN void *svGetArrElemPtr3(const svOpenArrayHandle, int indx1, int indx2,
|
||||
int indx3);
|
||||
|
||||
/*
|
||||
* Functions for copying between simulator storage and user space.
|
||||
* These functions copy the whole packed array in either direction.
|
||||
* The user is responsible for allocating an array to hold the
|
||||
* canonical representation.
|
||||
*/
|
||||
|
||||
/* s=source, d=destination */
|
||||
/* From user space into simulator storage */
|
||||
XXTERN void svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1);
|
||||
XXTERN void svPutBitArrElem2VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutBitArrElem3VecVal(const svOpenArrayHandle d, const svBitVecVal* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
XXTERN void svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutLogicArrElem1VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1);
|
||||
XXTERN void svPutLogicArrElem2VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutLogicArrElem3VecVal(const svOpenArrayHandle d, const svLogicVecVal* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
/* From simulator storage into user space */
|
||||
XXTERN void svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetBitArrElem1VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetBitArrElem2VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetBitArrElem3VecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
XXTERN void svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetLogicArrElem1VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetLogicArrElem2VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetLogicArrElem3VecVal(svLogicVecVal* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
XXTERN svBit svGetBitArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svBit svGetBitArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svBit svGetBitArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svBit svGetBitArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3);
|
||||
XXTERN svLogic svGetLogicArrElem(const svOpenArrayHandle s, int indx1, ...);
|
||||
XXTERN svLogic svGetLogicArrElem1(const svOpenArrayHandle s, int indx1);
|
||||
XXTERN svLogic svGetLogicArrElem2(const svOpenArrayHandle s, int indx1, int indx2);
|
||||
XXTERN svLogic svGetLogicArrElem3(const svOpenArrayHandle s, int indx1, int indx2,
|
||||
int indx3);
|
||||
XXTERN void svPutLogicArrElem(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
...);
|
||||
XXTERN void svPutLogicArrElem1(const svOpenArrayHandle d, svLogic value, int indx1);
|
||||
XXTERN void svPutLogicArrElem2(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
int indx2);
|
||||
XXTERN void svPutLogicArrElem3(const svOpenArrayHandle d, svLogic value, int indx1,
|
||||
int indx2, int indx3);
|
||||
XXTERN void svPutBitArrElem(const svOpenArrayHandle d, svBit value, int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1(const svOpenArrayHandle d, svBit value, int indx1);
|
||||
XXTERN void svPutBitArrElem2(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
int indx2);
|
||||
XXTERN void svPutBitArrElem3(const svOpenArrayHandle d, svBit value, int indx1,
|
||||
int indx2, int indx3);
|
||||
|
||||
/* Functions for working with DPI context */
|
||||
|
||||
/*
|
||||
* Retrieve the active instance scope currently associated with the executing
|
||||
* imported function. Unless a prior call to svSetScope has occurred, this
|
||||
* is the scope of the function's declaration site, not call site.
|
||||
* Returns NULL if called from C code that is *not* an imported function.
|
||||
*/
|
||||
XXTERN svScope svGetScope();
|
||||
|
||||
/*
|
||||
* Set context for subsequent export function execution.
|
||||
* This function must be called before calling an export function, unless
|
||||
* the export function is called while executing an import function. In that
|
||||
* case the export function shall inherit the scope of the surrounding import
|
||||
* function. This is known as the "default scope".
|
||||
* The return is the previous active scope (per svGetScope)
|
||||
*/
|
||||
XXTERN svScope svSetScope(const svScope scope);
|
||||
|
||||
/* Gets the fully qualified name of a scope handle */
|
||||
XXTERN const char* svGetNameFromScope(const svScope);
|
||||
|
||||
/*
|
||||
* Retrieve svScope to instance scope of an arbitrary function declaration.
|
||||
* (can be either module, program, interface, or generate scope)
|
||||
* The return value shall be NULL for unrecognized scope names.
|
||||
*/
|
||||
XXTERN svScope svGetScopeFromName(const char* scopeName);
|
||||
|
||||
/*
|
||||
* Store an arbitrary user data pointer for later retrieval by svGetUserData()
|
||||
* The userKey is generated by the user. It must be guaranteed by the user to
|
||||
* be unique from all other userKey's for all unique data storage requirements
|
||||
* It is recommended that the address of static functions or variables in the
|
||||
* user's C code be used as the userKey.
|
||||
* It is illegal to pass in NULL values for either the scope or userData
|
||||
* arguments. It is also an error to call svPutUserData() with an invalid
|
||||
* svScope. This function returns -1 for all error cases, 0 upon success. It is
|
||||
* suggested that userData values of 0 (NULL) not be used as otherwise it can
|
||||
* be impossible to discern error status returns when calling svGetUserData()
|
||||
*/
|
||||
XXTERN int svPutUserData(const svScope scope, void *userKey, void* userData);
|
||||
|
||||
/*
|
||||
* Retrieve an arbitrary user data pointer that was previously
|
||||
* stored by a call to svPutUserData(). See the comment above
|
||||
* svPutUserData() for an explanation of userKey, as well as
|
||||
* restrictions on NULL and illegal svScope and userKey values.
|
||||
* This function returns NULL for all error cases, 0 upon success.
|
||||
* This function also returns NULL in the event that a prior call
|
||||
* to svPutUserData() was never made.
|
||||
*/
|
||||
XXTERN void* svGetUserData(const svScope scope, void* userKey);
|
||||
|
||||
/*
|
||||
* Returns the file and line number in the SV code from which the import call
|
||||
* was made. If this information available, returns TRUE and updates fileName
|
||||
* and lineNumber to the appropriate values. Behavior is unpredictable if
|
||||
* fileName or lineNumber are not appropriate pointers. If this information is
|
||||
* not available return FALSE and contents of fileName and lineNumber not
|
||||
* modified. Whether this information is available or not is implementation-
|
||||
* specific. Note that the string provided (if any) is owned by the SV
|
||||
* implementation and is valid only until the next call to any SV function.
|
||||
* Applications must not modify this string or free it
|
||||
*/
|
||||
XXTERN int svGetCallerInfo(const char** fileName, int *lineNumber);
|
||||
|
||||
/*
|
||||
* Returns 1 if the current execution thread is in the disabled state.
|
||||
* Disable protocol must be adhered to if in the disabled state.
|
||||
*/
|
||||
XXTERN int svIsDisabledState();
|
||||
|
||||
/*
|
||||
* Imported functions call this API function during disable processing to
|
||||
* acknowledge that they are correctly participating in the DPI disable protocol.
|
||||
* This function must be called before returning from an imported function that is
|
||||
* in the disabled state.
|
||||
*/
|
||||
XXTERN void svAckDisabledState();
|
||||
|
||||
/*
|
||||
**********************************************************
|
||||
* DEPRECATED PORTION OF FILE STARTS FROM HERE.
|
||||
* IEEE-1800-compliant tools may not provide
|
||||
* support for the following functionality.
|
||||
**********************************************************
|
||||
*/
|
||||
|
||||
/*
|
||||
* Canonical representation of packed arrays
|
||||
* 2-state and 4-state vectors, modeled upon PLI's avalue/bvalue
|
||||
*/
|
||||
#define SV_CANONICAL_SIZE(WIDTH) (((WIDTH)+31)>>5)
|
||||
typedef unsigned int svBitVec32;/* (a chunk of) packed bit array */
|
||||
typedef struct { unsigned int c; unsigned int d;}
|
||||
svLogicVec32; /* (a chunk of) packed logic array */
|
||||
|
||||
/* reference to a standalone packed array */
|
||||
typedef void* svBitPackedArrRef;
|
||||
typedef void* svLogicPackedArrRef;
|
||||
|
||||
/*
|
||||
* total size in bytes of the simulator's representation of a packed array
|
||||
* width in bits
|
||||
*/
|
||||
XXTERN int svSizeOfBitPackedArr(int width);
|
||||
XXTERN int svSizeOfLogicPackedArr(int width);
|
||||
|
||||
/* Translation between the actual representation and the canonical representation */
|
||||
|
||||
/* s=source, d=destination, w=width */
|
||||
/* actual <-- canonical */
|
||||
XXTERN void svPutBitVec32(svBitPackedArrRef d, const svBitVec32* s, int w);
|
||||
XXTERN void svPutLogicVec32(svLogicPackedArrRef d, const svLogicVec32* s, int w);
|
||||
|
||||
/* canonical <-- actual */
|
||||
XXTERN void svGetBitVec32(svBitVec32* d, const svBitPackedArrRef s, int w);
|
||||
XXTERN void svGetLogicVec32(svLogicVec32* d, const svLogicPackedArrRef s, int w);
|
||||
|
||||
/*
|
||||
* Bit-select functions
|
||||
* Packed arrays are assumed to be indexed n-1:0,
|
||||
* where 0 is the index of LSB
|
||||
*/
|
||||
|
||||
/* s=source, i=bit-index */
|
||||
XXTERN svBit svGetSelectBit(const svBitPackedArrRef s, int i);
|
||||
XXTERN svLogic svGetSelectLogic(const svLogicPackedArrRef s, int i);
|
||||
|
||||
/* d=destination, i=bit-index, s=scalar */
|
||||
XXTERN void svPutSelectBit(svBitPackedArrRef d, int i, svBit s);
|
||||
XXTERN void svPutSelectLogic(svLogicPackedArrRef d, int i, svLogic s);
|
||||
|
||||
/*
|
||||
* functions for part-select
|
||||
*
|
||||
* a narrow (<=32 bits) part-select is copied between
|
||||
* the implementation representation and a single chunk of
|
||||
* canonical representation
|
||||
* Normalized ranges and indexing [n-1:0] are used for both arrays:
|
||||
* the array in the implementation representation and the canonical array.
|
||||
*
|
||||
* s=source, d=destination, i=starting bit index, w=width
|
||||
* like for variable part-selects; limitations: w <= 32
|
||||
*/
|
||||
|
||||
/* canonical <-- actual */
|
||||
XXTERN void svGetPartSelectBit(svBitVec32* d, const svBitPackedArrRef s,
|
||||
int i, int w);
|
||||
XXTERN svBitVec32 svGetBits(const svBitPackedArrRef s, int i, int w);
|
||||
XXTERN svBitVec32 svGet32Bits(const svBitPackedArrRef s, int i); /* 32-bits */
|
||||
|
||||
XXTERN uint64_t svGet64Bits(const svBitPackedArrRef s, int i);
|
||||
|
||||
/* 64-bits */
|
||||
XXTERN void svGetPartSelectLogic(svLogicVec32* d, const svLogicPackedArrRef s,
|
||||
int i, int w);
|
||||
/* actual <-- canonical */
|
||||
XXTERN void svPutPartSelectBit(svBitPackedArrRef d, const svBitVec32 s,
|
||||
int i, int w);
|
||||
XXTERN void svPutPartSelectLogic(svLogicPackedArrRef d, const svLogicVec32* s,
|
||||
int i, int w);
|
||||
|
||||
/*
|
||||
* Functions for open array translation between simulator and canonical
|
||||
* representations. These functions copy the whole packed array in either
|
||||
* direction. The user is responsible for allocating an array in the
|
||||
* canonical representation.
|
||||
*/
|
||||
|
||||
/* s=source, d=destination */
|
||||
/* actual <-- canonical */
|
||||
XXTERN void svPutBitArrElemVec32(const svOpenArrayHandle d, const svBitVec32* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutBitArrElem1Vec32(const svOpenArrayHandle d, const svBitVec32* s,
|
||||
int indx1);
|
||||
XXTERN void svPutBitArrElem2Vec32(const svOpenArrayHandle d, const svBitVec32* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutBitArrElem3Vec32(const svOpenArrayHandle d, const svBitVec32* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
XXTERN void svPutLogicArrElemVec32(const svOpenArrayHandle d, const svLogicVec32* s,
|
||||
int indx1, ...);
|
||||
XXTERN void svPutLogicArrElem1Vec32(const svOpenArrayHandle d, const svLogicVec32* s,
|
||||
int indx1);
|
||||
XXTERN void svPutLogicArrElem2Vec32(const svOpenArrayHandle d, const svLogicVec32* s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svPutLogicArrElem3Vec32(const svOpenArrayHandle d, const svLogicVec32* s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
/* canonical <-- actual */
|
||||
XXTERN void svGetBitArrElemVec32(svBitVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetBitArrElem1Vec32(svBitVec32* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetBitArrElem2Vec32(svBitVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetBitArrElem3Vec32(svBitVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
XXTERN void svGetLogicArrElemVec32(svLogicVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, ...);
|
||||
XXTERN void svGetLogicArrElem1Vec32(svLogicVec32* d, const svOpenArrayHandle s,
|
||||
int indx1);
|
||||
XXTERN void svGetLogicArrElem2Vec32(svLogicVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2);
|
||||
XXTERN void svGetLogicArrElem3Vec32(svLogicVec32* d, const svOpenArrayHandle s,
|
||||
int indx1, int indx2, int indx3);
|
||||
|
||||
/*
|
||||
**********************************************************
|
||||
* DEPRECATED PORTION OF FILE ENDS HERE.
|
||||
**********************************************************
|
||||
*/
|
||||
|
||||
#undef DPI_EXTERN
|
||||
|
||||
#ifdef DPI_PROTOTYPES
|
||||
#undef DPI_PROTOTYPES
|
||||
#undef XXTERN
|
||||
#undef EETERN
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -124,7 +124,7 @@ if [ x"$dir_arg" != x ]; then
|
||||
else
|
||||
|
||||
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# might cause directories to be created, which would be especially bad
|
||||
# if $src (and thus $dsttmp) contains '*'.
|
||||
|
||||
if [ -f $src -o -d $src ]
|
||||
@@ -134,7 +134,7 @@ else
|
||||
echo "install: $src does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
if [ x"$dst" = x ]
|
||||
then
|
||||
echo "install: no destination specified"
|
||||
@@ -162,7 +162,7 @@ dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
|
||||
|
||||
# Skip lots of stat calls in the usual case.
|
||||
if [ ! -d "$dstdir" ]; then
|
||||
defaultIFS='
|
||||
defaultIFS='
|
||||
'
|
||||
IFS="${IFS-${defaultIFS}}"
|
||||
|
||||
@@ -201,17 +201,17 @@ else
|
||||
|
||||
# If we're going to rename the final executable, determine the name now.
|
||||
|
||||
if [ x"$transformarg" = x ]
|
||||
if [ x"$transformarg" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
dstfile=`basename $dst $transformbasename |
|
||||
sed $transformarg`$transformbasename
|
||||
fi
|
||||
|
||||
# don't allow the sed command to completely eliminate the filename
|
||||
|
||||
if [ x"$dstfile" = x ]
|
||||
if [ x"$dstfile" = x ]
|
||||
then
|
||||
dstfile=`basename $dst`
|
||||
else
|
||||
@@ -242,7 +242,7 @@ else
|
||||
# Now rename the file to the real destination.
|
||||
|
||||
$doit $rmcmd -f $dstdir/$dstfile &&
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
$doit $mvcmd $dsttmp $dstdir/$dstfile
|
||||
|
||||
fi &&
|
||||
|
||||
|
||||
+794
@@ -0,0 +1,794 @@
|
||||
# DESCRIPTION: DOCUMENT source run through perl to produce internals.txt file
|
||||
# Use 'make internals.txt' to produce the output file
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Verilator Internals
|
||||
|
||||
=head1 INTRODUCTION
|
||||
|
||||
This file discusses internal and programming details for Verilator. It's
|
||||
the first for reference for developers and debugging problems.
|
||||
|
||||
See also the Verilator internals presentation at http://www.veripool.org.
|
||||
|
||||
=head1 CODE FLOWS
|
||||
|
||||
=head2 Verilator Flow
|
||||
|
||||
The main flow of Verilator can be followed by reading the Verilator.cpp
|
||||
process() function:
|
||||
|
||||
First, the files specified on the command line are read. Reading involves
|
||||
preprocessing, then lexical analysis with Flex and parsing with Bison.
|
||||
This produces an abstract syntax tree (AST) representation of the design,
|
||||
which is what is visible in the .tree files described below.
|
||||
|
||||
Verilator then makes a series of passes over the AST, progressively refining
|
||||
and optimizing it.
|
||||
|
||||
Cells in the AST first linked, which will read and parse additional files as
|
||||
above.
|
||||
|
||||
Functions, variable and other references are linked to their definitions.
|
||||
|
||||
Parameters are resolved and the design is elaborated.
|
||||
|
||||
Verilator then performs many additional edits and optimizations on the
|
||||
hierarchical design. This includes coverage, assertions, X elimination,
|
||||
inlining, constant propagation, and dead code elimination.
|
||||
|
||||
References in the design are then pseudo-flattened. Each module's variables
|
||||
and functions get "Scope" references. A scope reference is an occurrence of
|
||||
that un-flattened variable in the flattened hierarchy. A module that occurs
|
||||
only once in the hierarchy will have a single scope and single VarScope for
|
||||
each variable. A module that occurs twice will have a scope for each
|
||||
occurrence, and two VarScopes for each variable. This allows optimizations
|
||||
to proceed across the flattened design, while still preserving the
|
||||
hierarchy.
|
||||
|
||||
Additional edits and optimizations proceed on the pseudo-flat design. These
|
||||
include module references, function inlining, loop unrolling, variable
|
||||
lifetime analysis, lookup table creation, always splitting, and logic gate
|
||||
simplifications (pushing inverters, etc).
|
||||
|
||||
Verilator orders the code. Best case, this results in a single "eval"
|
||||
function which has all always statements flowing from top to bottom with no
|
||||
loops.
|
||||
|
||||
Verilator mostly removes the flattening, so that code may be shared between
|
||||
multiple invocations of the same module. It localizes variables, combines
|
||||
identical functions, expands macros to C primitives, adds branch prediction
|
||||
hints, and performs additional constant propagation.
|
||||
|
||||
Verilator finally writes the C++ modules.
|
||||
|
||||
=head2 Key Classes Used in the Verilator Flow
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<AstNode>
|
||||
|
||||
The AST is represented at the top level by the class C<AstNode>. This abstract
|
||||
class has derived classes for the individual components (e.g. C<AstGenerate>
|
||||
for a generate block) or groups of components (e.g. C<AstNodeFTask> for
|
||||
functions and tasks, which in turn has C<AstFunc> and C<AstTask> as derived
|
||||
classes).
|
||||
|
||||
Each C<AstNode> has pointers to up to four children, accessed by the
|
||||
C<op1p> through C<op4p> methods. These methods are then abstracted in a
|
||||
specific Ast* node class to a more specific name. For example with the
|
||||
C<AstIf> node (for C<if> statements), C<ifsp> calls C<op2p> to give the
|
||||
pointer to the AST for the "then" block, while C<elsesp> calls C<op3p> to
|
||||
give the pointer to the AST for the "else" block, or NULL if there is not
|
||||
one.
|
||||
|
||||
C<AstNode> has the concept of a next and previous AST - for example the
|
||||
next and previous statements in a block. Pointers to the AST for these
|
||||
statements (if they exist) can be obtained using the C<back> and C<next>
|
||||
methods.
|
||||
|
||||
It is useful to remember that the derived class C<AstNetlist> is at the top
|
||||
of the tree, so checking for this class is the standard way to see if you
|
||||
are at the top of the tree.
|
||||
|
||||
By convention, each function/method uses the variable C<nodep> as a pointer
|
||||
to the C<AstNode> currently being processed.
|
||||
|
||||
=item C<AstNVisitor>
|
||||
|
||||
The passes are implemented by AST visitor classes (see L</Visitor
|
||||
Functions>). These are implemented by subclasses of the abstract class,
|
||||
C<AstNVisitor>. Each pass creates an instance of the visitor class, which
|
||||
in turn implements a method to perform the pass.
|
||||
|
||||
=item C<V3Graph>
|
||||
|
||||
A number of passes use graph algorithms, and the class C<V3Graph> is provided
|
||||
to represent those graphs. Graphs are directed, and algorithms are provided to
|
||||
manipulate the graphs and to output them in I<GraphViz> dot format (see
|
||||
L<http://www.graphviz.org/>). C<V3Graph.h> provides documentation of this
|
||||
class.
|
||||
|
||||
=item C<V3GraphVertex>
|
||||
|
||||
This is the base class for vertices in a graph. Vertices have an associated
|
||||
C<fanout>, C<color> and C<rank>, which may be used in algorithms for ordering
|
||||
the graph. A generic C<user>/C<userp> member variable is also provided.
|
||||
|
||||
Virtual methods are provided to specify the name, color, shape and style to be
|
||||
used in dot output. Typically users provide derived classes from
|
||||
C<V3GraphVertex> which will reimplement these methods.
|
||||
|
||||
Iterators are provided to access in and out edges. Typically these are used in
|
||||
the form:
|
||||
|
||||
for (V3GraphEdge *edgep = vertexp->inBeginp();
|
||||
edgep;
|
||||
edgep = edgep->inNextp()) {
|
||||
|
||||
=item C<V3GraphEdge>
|
||||
|
||||
This is the base class for directed edges between pairs of vertices. Edges
|
||||
have an associated C<weight> and may also be made C<cutable>. A generic
|
||||
C<user>/C<userp> member variable is also provided.
|
||||
|
||||
Accessors, C<fromp> and C<top> return the "from" and "to" vertices
|
||||
respectively.
|
||||
|
||||
Virtual methods are provided to specify the label, color and style to be
|
||||
used in dot output. Typically users provided derived classes from
|
||||
C<V3GraphEdge> which will reimplement these methods.
|
||||
|
||||
=item C<V3GraphAlg>
|
||||
|
||||
This is the base class for graph algorithms. It implements a C<bool> method,
|
||||
C<followEdge> which algorithms can use to decide whether an edge is
|
||||
followed. This method returns true if the graph edge has weight greater than
|
||||
one and a user function, C<edgeFuncp> (supplied in the constructor) returns
|
||||
C<true>.
|
||||
|
||||
A number of predefined derived algorithm classes and access methods are
|
||||
provided and documented in C<V3GraphAlg.cpp>.
|
||||
|
||||
=back
|
||||
|
||||
=head2 Verilated Flow
|
||||
|
||||
The evaluation loop outputted by Verilator is designed to allow a single
|
||||
function to perform evaluation under most situations.
|
||||
|
||||
On the first evaluation, the Verilated code calls initial blocks, and then
|
||||
"settles" the modules, by evaluating functions (from always statements)
|
||||
until all signals are stable.
|
||||
|
||||
On other evaluations, the Verilated code detects what input signals have
|
||||
changes. If any are clocks, it calls the appropriate sequential functions
|
||||
(from always @ posedge statements). Interspersed with sequential functions
|
||||
it calls combo functions (from always @*). After this is complete, it
|
||||
detects any changes due to combo loops or internally generated clocks, and
|
||||
if one is found must reevaluate the model again.
|
||||
|
||||
For SystemC code, the eval() function is wrapped in a SystemC SC_METHOD,
|
||||
sensitive to all inputs. (Ideally it would only be sensitive to clocks and
|
||||
combo inputs, but tracing requires all signals to cause evaluation, and the
|
||||
performance difference is small.)
|
||||
|
||||
If tracing is enabled, a callback examines all variables in the design for
|
||||
changes, and writes the trace for each change. To accelerate this process
|
||||
the evaluation process records a bitmask of variables that might have
|
||||
changed; if clear, checking those signals for changes may be skipped.
|
||||
|
||||
=head1 CODING CONVENTIONS
|
||||
|
||||
=head2 Indentation style
|
||||
|
||||
To match the indentation of Verilator C++ sources, use 4 spaces per level,
|
||||
and leave tabs at 8 columns, so every other indent level is a tab stop.
|
||||
|
||||
All files should contain the magic header to insure standard indentation:
|
||||
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
|
||||
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.)
|
||||
|
||||
=head2 The C<astgen> script
|
||||
|
||||
Some of the code implementing passes is extremely repetitive, and must be
|
||||
implemented for each sub-class of C<AstNode>. However, while repetitive,
|
||||
there is more variability than can be handled in C++ macros.
|
||||
|
||||
In Verilator this is implemented by using a Perl script, C<astgen> to
|
||||
pre-process the C++ code. For example in C<V3Const.cpp> this is used to
|
||||
implement the C<visit()> functions for each binary operation using the
|
||||
TREEOP macro.
|
||||
|
||||
The original C++ source code is transformed into C++ code in the C<obj_opt>
|
||||
and C<obj_dbg> sub-directories (the former for the optimized version of
|
||||
Verilator, the latter for the debug version). So for example C<V3Const.cpp>
|
||||
into C<V3Const__gen.cpp>.
|
||||
|
||||
=head2 Visitor Functions
|
||||
|
||||
Verilator uses the I<Visitor> design pattern to implement its refinement
|
||||
and optimization passes. This allows separation of the pass algorithm from
|
||||
the AST on which it operates. Wikipedia provides an introduction to the
|
||||
concept at L<http://en.wikipedia.org/wiki/Visitor_pattern>.
|
||||
|
||||
As noted above, all visitors are derived classes of C<AstNVisitor>. All
|
||||
derived classes of C<AstNode> implement the C<accept> method, which takes
|
||||
as argument a reference to an instance or a C<AstNVisitor> derived class
|
||||
and applies the visit method of the C<AstNVisitor> to the invoking AstNode
|
||||
instance (i.e. C<this>).
|
||||
|
||||
One possible difficulty is that a call to C<accept> may perform an edit
|
||||
which destroys the node it receives as argument. The
|
||||
C<acceptSubtreeReturnEdits> method of C<AstNode> is provided to apply
|
||||
C<accept> and return the resulting node, even if the original node is
|
||||
destroyed (if it is not destroyed it will just return the original node).
|
||||
|
||||
The behavior of the visitor classes is achieved by overloading the C<visit>
|
||||
function for the different C<AstNode> derived classes. If a specific
|
||||
implementation is not found, the system will look in turn for overloaded
|
||||
implementations up the inheritance hierarchy. For example calling C<accept>
|
||||
on C<AstIf> will look in turn for:
|
||||
|
||||
void visit (AstIf* nodep, AstNUser* vup)
|
||||
void visit (AstNodeIf* nodep, AstNUser* vup)
|
||||
void visit (AstNodeStmt* nodep, AstNUser* vup)
|
||||
void visit (AstNode* nodep, AstNUser* vup)
|
||||
|
||||
There are three ways data is passed between visitor functions.
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1.
|
||||
|
||||
A visitor-class member variable. This is generally for passing "parent"
|
||||
information down to children. C<m_modp> is a common example. It's set to
|
||||
NULL in the constructor, where that node (C<AstModule> visitor) sets it,
|
||||
then the children are iterated, then it's cleared. Children under an
|
||||
C<AstModule> will see it set, while nodes elsewhere will see it clear. If
|
||||
there can be nested items (for example an C<AstFor> under an C<AstFor>) the
|
||||
variable needs to be save-set-restored in the C<AstFor> visitor, otherwise
|
||||
exiting the lower for will lose the upper for's setting.
|
||||
|
||||
=item 2.
|
||||
|
||||
User attributes. Each C<AstNode> (B<Note.> The AST node, not the visitor)
|
||||
has five user attributes, which may be accessed as an integer using the
|
||||
C<user1()> through C<user5()> methods, or as a pointer (of type
|
||||
C<AstNUser>) using the C<user1p()> through C<user5p()> methods (a common
|
||||
technique lifted from graph traversal packages).
|
||||
|
||||
A visitor first clears the one it wants to use by calling
|
||||
C<AstNode::user#ClearTree()>, then it can mark any node's user() with whatever
|
||||
data it wants. Readers just call C<< nodep->user() >>, but may need to cast
|
||||
appropriately, so you'll often see C<< nodep->userp()->castSOMETYPE() >>. At
|
||||
the top of each visitor are comments describing how the C<user()> stuff
|
||||
applies to that visitor class. For example:
|
||||
|
||||
// NODE STATE
|
||||
// Cleared entire netlist
|
||||
// AstModule::user1p() // bool. True to inline this module
|
||||
|
||||
This says that at the C<AstNetlist> C<user1ClearTree()> is called. Each
|
||||
C<AstModule>'s C<user1()> is used to indicate if we're going to inline it.
|
||||
|
||||
These comments are important to make sure a C<user#()> on a given C<AstNode>
|
||||
type is never being used for two different purposes.
|
||||
|
||||
Note that calling C<user#ClearTree> is fast, it doesn't walk the tree, so
|
||||
it's ok to call fairly often. For example, it's commonly called on every
|
||||
module.
|
||||
|
||||
=item 3.
|
||||
|
||||
Parameters can be passed between the visitors in close to the "normal"
|
||||
function caller to callee way. This is the second C<vup> parameter of type
|
||||
C<AstNUser> that is ignored on most of the visitor functions. V3Width does
|
||||
this, but it proved more messy than the above and is deprecated. (V3Width
|
||||
was nearly the first module written. Someday this scheme may be removed,
|
||||
as it slows the program down to have to pass vup everywhere.)
|
||||
|
||||
=back
|
||||
|
||||
=head2 Iterators
|
||||
|
||||
C<AstNode> provides a set of iterators to facilitate walking over the
|
||||
tree. Each takes two arguments, a visitor, C<v>, of type C<AstNVisitor> and
|
||||
an optional pointer user data, C<vup>, of type C<AstNUser*>. The second is
|
||||
one of the ways to pass parameters to visitors described in L</Visitor
|
||||
Functions>, but its use is now deprecated and should I<not> be used for new
|
||||
visitor classes.
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<iterate()>
|
||||
|
||||
This just applies the C<accept> method of the C<AstNode> to the visitor
|
||||
function.
|
||||
|
||||
=item C<iterateAndNextIgnoreEdit>
|
||||
|
||||
Applies the C<accept> method of each C<AstNode> in a list (i.e. connected
|
||||
by C<nextp> and C<backp> pointers).
|
||||
|
||||
=item C<iterateAndNext>
|
||||
|
||||
Applies the C<accept> method of each C<AstNode> in a list. If a node is
|
||||
edited by the call to C<accept>, apply C<accept> again, until the node does
|
||||
not change.
|
||||
|
||||
=item C<iterateListBackwards>
|
||||
|
||||
Applies the C<accept> method of each C<AstNode> in a list, starting with
|
||||
the last one.
|
||||
|
||||
=item C<iterateChildren>
|
||||
|
||||
Apply the C<iterateAndNext> method on each child C<op1p> through C<op4p> in
|
||||
turn.
|
||||
|
||||
=item C<iterateChildrenBackwards>
|
||||
|
||||
Apply the C<iterateListBackwards> method on each child C<op1p> through
|
||||
C<op4p> in turn.
|
||||
|
||||
=back
|
||||
|
||||
=head3 Caution on Using Iterators When Child Changes
|
||||
|
||||
Visitors often replace one node with another node; V3Width and V3Const are
|
||||
major examples. A visitor which is the parent of such a replacement needs
|
||||
to be aware that calling iteration may cause the children to change. For
|
||||
example:
|
||||
|
||||
// nodep->lhsp() is 0x1234000
|
||||
nodep->lhsp()->iterateAndNext(...); // and under covers nodep->lhsp() changes
|
||||
// nodep->lhsp() is 0x5678400
|
||||
nodep->lhsp()->iterateAndNext(...);
|
||||
|
||||
Will work fine, as even if the first iterate causes a new node to take the
|
||||
place of the lhsp(), that edit will update nodep->lhsp() and the second
|
||||
call will correctly see the change. Alternatively:
|
||||
|
||||
lp = nodep->lhsp();
|
||||
// nodep->lhsp() is 0x1234000, lp is 0x1234000
|
||||
lp->iterateAndNext(...); **lhsp=NULL;** // and under covers nodep->lhsp() changes
|
||||
// nodep->lhsp() is 0x5678400, lp is 0x1234000
|
||||
lp->iterateAndNext(...);
|
||||
|
||||
This will cause bugs or a core dump, as lp is a dangling pointer. Thus it
|
||||
is advisable to set lhsp=NULL shown in the *'s above to make sure these
|
||||
dangles are avoided. Another alternative used in special cases mostly in
|
||||
V3Width is to use acceptSubtreeReturnEdits, which operates on a single node
|
||||
and returns the new pointer if any. Note acceptSubtreeReturnEdits does not
|
||||
follow nextp() links.
|
||||
|
||||
lp = lp->acceptSubtreeReturnEdits()
|
||||
|
||||
=head2 Identifying derived classes
|
||||
|
||||
A common requirement is to identify the specific C<AstNode> class we are
|
||||
dealing with. For example a visitor might not implement separate C<visit>
|
||||
methods for C<AstIf> and C<AstGenIf>, but just a single method for the base
|
||||
class:
|
||||
|
||||
void visit (AstNodeIf* nodep, AstNUser* vup)
|
||||
|
||||
However that method might want to specify additional code if it is called
|
||||
for C<AstGenIf>. Verilator does this by providing a C<castSOMETYPE()>
|
||||
method for each possible node type, using C++ C<dynamic_cast>. This either
|
||||
returns a pointer to the object cast to that type (if it is of class
|
||||
C<SOMETYPE>, or a derived class of C<SOMETYPE>) or else NULL. So our
|
||||
C<visit> method could use:
|
||||
|
||||
if (nodep->castAstGenIf()) {
|
||||
<code specific to AstGenIf>
|
||||
}
|
||||
|
||||
A common test is for C<AstNetlist>, which is the node at the root of the
|
||||
AST.
|
||||
|
||||
=head1 TESTING
|
||||
|
||||
For an overview of how to write a test see the BUGS section of the
|
||||
Verilator primary manual.
|
||||
|
||||
It is important to add tests for failures as well as success (for example to
|
||||
check that an error message is correctly triggered).
|
||||
|
||||
Tests that fail should by convention have the suffix C<_bad> in their name,
|
||||
and include C<fails =E<gt> 1> in either their C<compile> or C<execute> step as
|
||||
appropriate.
|
||||
|
||||
=head2 Preparing to Run Tests
|
||||
|
||||
For all tests to pass you must install the following packages:
|
||||
|
||||
* SystemC to compile the SystemC outputs, see http://systemc.org
|
||||
|
||||
* Parallel::Forker from CPAN to run tests in parallel, you can install this
|
||||
with e.g. "sudo cpan install Parallel::Forker".
|
||||
|
||||
* vcddiff to find differences in VCD outputs. See the readme at
|
||||
https://github.com/veripool/vcddiff
|
||||
|
||||
=head2 Controlling the Test Driver
|
||||
|
||||
Test drivers are written in PERL. All invoke the main test driver script,
|
||||
which can provide detailed help on all the features available when writing
|
||||
a test driver.
|
||||
|
||||
test_regress/t/driver.pl --help
|
||||
|
||||
For convenience, a summary of the most commonly used features is provided
|
||||
here. All drivers require a call to C<compile> subroutine to compile the
|
||||
test. For run-time tests, this is followed by a call to the C<execute>
|
||||
subroutine. Both of these functions can optionally be provided with a hash
|
||||
table as argument specifying additional options.
|
||||
|
||||
The test driver assumes by default that the source Verilog file name
|
||||
matches the PERL driver name. So a test whose driver is C<t/t_mytest.pl>
|
||||
will expect a Verilog source file C<t/t_mytest.v>. This can be changed
|
||||
using the C<top_filename> subroutine, for example
|
||||
|
||||
top_filename("t/t_myothertest.v");
|
||||
|
||||
By default all tests will run with major simulators (Icarus Verilog, NC,
|
||||
VCS, ModelSim) as well as Verilator, to allow results to be
|
||||
compared. However if you wish a test only to be used with Verilator, you
|
||||
can use the following:
|
||||
|
||||
$Self->{vlt} or $Self->skip("Verilator only test");
|
||||
|
||||
Of the many options that can be set through arguments to C<compiler> and
|
||||
C<execute>, the following are particularly useful:
|
||||
|
||||
=over 4
|
||||
|
||||
=item C<verilator_flags2>
|
||||
|
||||
A list of flags to be passed to verilator when compiling.
|
||||
|
||||
=item C<fails>
|
||||
|
||||
Set to 1 to indicate that the compilation or execution is intended to fail.
|
||||
|
||||
=back
|
||||
|
||||
For example the following would specify that compilation requires two
|
||||
defines and is expected to fail.
|
||||
|
||||
compile (
|
||||
verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
|
||||
fails => 1,
|
||||
);
|
||||
|
||||
=head2 Regression Testing for Developers
|
||||
|
||||
Developers will also want to call ./configure with two extra flags:
|
||||
|
||||
=over 4
|
||||
|
||||
=item --enable-ccwarn
|
||||
|
||||
Causes the build to stop on warnings as well as errors. A good way to
|
||||
ensure no sloppy code gets added, however it can be painful when it comes
|
||||
to testing, since third party code used in the tests (e.g. SystemC) may not
|
||||
be warning free.
|
||||
|
||||
=item --enable-longtests
|
||||
|
||||
In addition to the standard C, SystemC tests also run the tests in the
|
||||
C<test_verilated> and C<test_regress> directories when using I<make test>.
|
||||
This is disabled by default as SystemC installation problems would
|
||||
otherwise falsely indicate a Verilator problem.
|
||||
|
||||
=back
|
||||
|
||||
When enabling the long tests, some additional PERL modules are needed, which
|
||||
you can install using cpan.
|
||||
|
||||
cpan install Unix::Processors
|
||||
|
||||
There are some traps to avoid when running regression tests
|
||||
|
||||
=over 4
|
||||
|
||||
=item *
|
||||
|
||||
When checking the MANIFEST, the test will barf on unexpected code in the
|
||||
Verilator tree. So make sure to keep any such code outside the tree.
|
||||
|
||||
=item *
|
||||
|
||||
Not all Linux systems install Perldoc by default. This is needed for the
|
||||
I<--help> option to Verilator, and also for regression testing. This can be
|
||||
installed using cpan:
|
||||
|
||||
cpan install Pod::Perldoc
|
||||
|
||||
Many Linux systems also offer a standard package for this. Red
|
||||
Hat/Fedora/Centos offer I<perl-Pod-Perldoc>, while Debian/Ubuntu/Linux Mint
|
||||
offer I<perl-doc>.
|
||||
|
||||
=item *
|
||||
|
||||
Running regression may exhaust resources on some Linux systems, particularly
|
||||
file handles and user processes. Increase these to respectively 16,384 and
|
||||
4,096. The method of doing this is system dependent, but on Fedora Linux it
|
||||
would require editing the C</etc/security/limits.conf> file as root.
|
||||
|
||||
=back
|
||||
|
||||
=head1 DEBUGGING
|
||||
|
||||
=head2 --debug
|
||||
|
||||
When you run with --debug there are two primary output file types placed into
|
||||
the obj_dir, .tree and .dot files.
|
||||
|
||||
=head2 .dot output
|
||||
|
||||
Dot files are dumps of internal graphs in Graphviz
|
||||
L<http://www.graphviz.org/> dot format. When a dot file is dumped,
|
||||
Verilator will also print a line on stdout that can be used to format the
|
||||
output, for example:
|
||||
|
||||
dot -Tps -o ~/a.ps obj_dir/Vtop_foo.dot
|
||||
|
||||
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 ZGRViewer
|
||||
L<http://zvtm.sourceforge.net/zgrviewer.html>. If you know of better
|
||||
viewers let us know; ZGRViewer isn't great for large graphs.
|
||||
|
||||
=head2 .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]
|
||||
|
||||
=over 4
|
||||
|
||||
The following summarizes the above example dump, with more detail on each
|
||||
field in the section below.
|
||||
|
||||
"1:2:" indicates the hierarchy of the C<VAR> is the C<op2p> pointer under
|
||||
the C<MODULE>, which in turn is the C<op1p> pointer under the C<NETLIST>
|
||||
|
||||
"VAR" is the AstNodeType.
|
||||
|
||||
"0x91a780" is the address of this node.
|
||||
|
||||
"<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.
|
||||
|
||||
"@dt=0x..." indicates the address of the data type this node contains.
|
||||
|
||||
"w32" indicates the width is 32 bits.
|
||||
|
||||
"out_wide" is the name of the node, in this case the name of the variable.
|
||||
|
||||
"[O]" are flags which vary with the type of node, in this case it means the
|
||||
variable is an output.
|
||||
|
||||
=back
|
||||
|
||||
In more detail the following fields are dumped common to all nodes. They
|
||||
are produced by the C<AstNode::dump()> method:
|
||||
|
||||
=over 4
|
||||
|
||||
=item Tree Hierarchy
|
||||
|
||||
The dump lines begin with numbers and colons to indicate the child node
|
||||
hierarchy. As noted above in L</Key Classes Used in the Verilator Flow>,
|
||||
C<AstNode> has lists of items at the same level in the AST, connected by
|
||||
the C<nextp()> and C<prevp()> pointers. These appear as nodes at the same
|
||||
level. For example after inlining:
|
||||
|
||||
NETLIST 0x929c1c8 <e1> {a0} w0
|
||||
1: MODULE 0x92bac80 <e3144> {e14} w0 TOP_t L1 [P]
|
||||
1:1: CELLINLINE 0x92bab18 <e3686#> {e14} w0 v -> t
|
||||
1:1: CELLINLINE 0x92bc1d8 <e3688#> {e24} w0 v__DOT__i_test_gen -> test_gen
|
||||
...
|
||||
1: MODULE 0x92b9bb0 <e503> {e47} w0 test_gen L3
|
||||
...
|
||||
|
||||
=item AstNode type
|
||||
|
||||
The textual name of this node AST type (always in capitals). Many of these
|
||||
correspond directly to Verilog entities (for example C<MODULE> and
|
||||
C<TASK>), but others are internal to Verialtor (for example C<NETLIST> and
|
||||
C<BASICDTYPE>).
|
||||
|
||||
=item Address of the node
|
||||
|
||||
A hexadecimal address of the node in memory. Useful for examining with the
|
||||
debugger.
|
||||
|
||||
=item Last edit number
|
||||
|
||||
Of the form C<< <ennnn> >> or C<< <ennnn#> >> , where C<nnnn> is the number
|
||||
of the last edit to modify this node. The trailing C<#> indicates the node
|
||||
has been edited since the last tree dump (which typically means in the last
|
||||
refinement or optimization pass). GDB can watch for this, see L</Debugging
|
||||
with GDB>.
|
||||
|
||||
=item Source file and line
|
||||
|
||||
Of the form C<< {xxnnnn} >>, where C{xx} is the filename letter (or
|
||||
letters) and C<nnnn> is the line number within that file. The first file is
|
||||
C<a>, the 26th is C<z>, the 27th is C<aa> and so on.
|
||||
|
||||
=item User pointers
|
||||
|
||||
Shows the value of the node's user1p...user5p, if non-NULL.
|
||||
|
||||
=item Data type
|
||||
|
||||
Many nodes have an explicit data type. "@dt=0x..." indicates the address
|
||||
of the data type (AstNodeDType) this node uses.
|
||||
|
||||
If a data type is present and is numeric, it then prints the width of the
|
||||
item. This field is a sequence of flag characters and width data as follows:
|
||||
|
||||
C<s> if the node is signed.
|
||||
|
||||
C<d> if the node is a double (i.e a floating point entity).
|
||||
|
||||
C<w> always present, indicating this is the width field.
|
||||
|
||||
C<u> if the node is unsized.
|
||||
|
||||
C</nnnn> if the node is unsized, where C<nnnn> is the minimum width.
|
||||
|
||||
=item Name of the entity represented by the node if it exists
|
||||
|
||||
For example for a C<VAR> it is the name of the variable.
|
||||
|
||||
=back
|
||||
|
||||
Many nodes follow these fields with additional node specific
|
||||
information. Thus the C<VARREF> node will print either C<[LV]> or C<[RV]>
|
||||
to indicate a left value or right value, followed by the node of the
|
||||
variable being referred to. For example:
|
||||
|
||||
1:2:1:1: VARREF 0x92c2598 <e509> {e24} w0 clk [RV] <- VAR 0x92a2e90 <e79> {e18} w0 clk [I] INPUT
|
||||
|
||||
In general, examine the C<dump()> method in C<V3AstNodes.cpp> of the node
|
||||
type in question to determine additional fields that may be printed.
|
||||
|
||||
The C<MODULE> has a list of C<CELLINLINE> nodes referred to by its
|
||||
C<op1p()> pointer, connected by C<nextp()> and C<prevp()> pointers.
|
||||
|
||||
Similarly the C<NETLIST> has a list of modules referred to by its C<op1p()>
|
||||
pointer.
|
||||
|
||||
=head2 Debugging with GDB
|
||||
|
||||
The test_regress/driver.pl script accepts --debug --gdb to start Verilator
|
||||
under gdb and break when an error is hit or the program is about to exit.
|
||||
You can also use --debug --gdbbt to just backtrace and then exit gdb. To
|
||||
debug the Verilated executable, use --gdbsim.
|
||||
|
||||
If you wish to start Verilator under GDB (or another debugger), then you
|
||||
can use --debug and look at the underlying invocation of verilator_dgb. For
|
||||
example
|
||||
|
||||
t/t_alw_dly.pl --debug
|
||||
|
||||
shows it invokes the command:
|
||||
|
||||
../verilator_bin_dbg --prefix Vt_alw_dly --x-assign unique --debug
|
||||
-cc -Mdir obj_dir/t_alw_dly --debug-check -f input.vc t/t_alw_dly.v
|
||||
|
||||
Start GDB, then C<start> with the remaining arguments.
|
||||
|
||||
gdb ../verilator_bin_dbg
|
||||
...
|
||||
(gdb) start --prefix Vt_alw_dly --x-assign unique --debug -cc -Mdir
|
||||
obj_dir/t_alw_dly --debug-check -f input.vc t/t_alw_dly.v
|
||||
> obj_dir/t_alw_dly/vlt_compile.log
|
||||
...
|
||||
Temporary breakpoint 1, main (argc=13, argv=0xbfffefa4, env=0xbfffefdc)
|
||||
at ../Verilator.cpp:615
|
||||
615 ios::sync_with_stdio();
|
||||
(gdb)
|
||||
|
||||
You can then continue execution with breakpoints as required.
|
||||
|
||||
To break at a specific edit number which changed a node (presumably to find
|
||||
what made a <e####> line in the tree dumps):
|
||||
|
||||
watch AstNode::s_editCntGbl==####
|
||||
|
||||
To print a node:
|
||||
|
||||
pn nodep
|
||||
# or: call nodep->dumpGdb() # aliased to "pn" in src/.gdbinit
|
||||
pnt nodep
|
||||
# or: call nodep->dumpTreeGdb() # aliased to "pnt" in src/.gdbinit
|
||||
|
||||
When GDB halts, it is useful to understand that the backtrace will commonly
|
||||
show the iterator functions between each invocation of C<visit> in the
|
||||
backtrace. You will typically see a frame sequence something like
|
||||
|
||||
...
|
||||
visit()
|
||||
iterateChildren()
|
||||
iterateAndNext()
|
||||
accept()
|
||||
visit()
|
||||
...
|
||||
|
||||
=head1 ADDING A NEW FEATURE
|
||||
|
||||
Generally what would you do to add a new feature?
|
||||
|
||||
=over 4
|
||||
|
||||
=item 1.
|
||||
|
||||
File a bug (if there isn't already) so others know what you're working on.
|
||||
|
||||
=item 2.
|
||||
|
||||
Make a testcase in the test_regress/t/t_EXAMPLE format, see L<TESTING>.
|
||||
|
||||
=item 3.
|
||||
|
||||
If grammar changes are needed, look at the git version of VerilogPerl's
|
||||
src/VParseGrammar.y, as this grammar supports the full SystemVerilog
|
||||
language and has a lot of back-and-forth with Verilator's grammar. Copy
|
||||
the appropriate rules to src/verilog.y and modify the productions.
|
||||
|
||||
=item 4.
|
||||
|
||||
If a new Ast type is needed, add it to V3AstNodes.h.
|
||||
|
||||
=back
|
||||
|
||||
Now you can run "test_regress/t/t_{new testcase}.pl --debug" and it'll
|
||||
probably fail but you'll see a test_regress/obj_dir/t_{newtestcase}/*.tree
|
||||
file which you can examine to see if the parsing worked. See also the
|
||||
sections above on debugging.
|
||||
|
||||
Modify the later visitor functions to process the new feature as needed.
|
||||
|
||||
=head2 Adding a new pass
|
||||
|
||||
For more substantial changes you may need to add a new pass. The simplest way
|
||||
to do this is to copy the C<.cpp> and C<.h> files from an existing
|
||||
pass. You'll need to add a call into your pass from the C<process()> function
|
||||
in C<src/verilator.cpp>.
|
||||
|
||||
To get your pass to build you'll need to add its binary filename to the list
|
||||
in C<src/Makefile_obj.in> and reconfigure.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
The latest version is available from L<http://www.veripool.org/>.
|
||||
|
||||
Copyright 2008-2017 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2007-2009 by Wilson Snyder. This package is free software; you
|
||||
# Copyright 2007-2017 by Wilson Snyder. This package is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -81,5 +81,5 @@ sub prep {
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# compile-command: "./bisondiff --unsup $WUP/Verilog/Parser/VParseBison.y ../src/verilog.y"
|
||||
# compile-command: "./bisondiff --unsup $VP/Parser/VParseBison.y ../src/verilog.y"
|
||||
# End:
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2007-2009 by Wilson Snyder. This package is free software; you
|
||||
# Copyright 2007-2017 by Wilson Snyder. This package is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
+2
-2
@@ -38,7 +38,7 @@ cwrite ("graph_export.cpp");
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ Displays this message and program version and exits.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
Copyright 2005-2017 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
+2
-2
@@ -43,7 +43,7 @@ dotwrite();
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ Displays this message and program version and exits.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
Copyright 2005-2017 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
+6
-3
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/perl -w
|
||||
######################################################################
|
||||
#
|
||||
# Copyright 2007-2009 by Wilson Snyder. This package is free software; you
|
||||
# Copyright 2007-2017 by Wilson Snyder. This package is free software; you
|
||||
# can redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
@@ -48,7 +48,10 @@ sub prep {
|
||||
|
||||
while (defined(my $line = $fh->getline)) {
|
||||
# Productions
|
||||
$line =~ s/[ \t]{[^}]*?}/\t{}/g;
|
||||
#$line =~ s/[ \t]{[^}]*?}/\t{}/g;
|
||||
$line =~ s/StashPrefix;//g;
|
||||
$line =~ s/VALTEXT;//g;
|
||||
$line =~ s/CALLBACK\([^)]*\);//g;
|
||||
push @lines, $line;
|
||||
}
|
||||
|
||||
@@ -57,5 +60,5 @@ sub prep {
|
||||
}
|
||||
|
||||
# Local Variables:
|
||||
# compile-command: "./flexdiff $WUP/Verilog/Parser/VParseLex.l ../src/verilog.l"
|
||||
# compile-command: "./flexdiff $VP/Parser/VParseLex.l ../src/verilog.l"
|
||||
# End:
|
||||
|
||||
Executable
+203
@@ -0,0 +1,203 @@
|
||||
#!/usr/bin/perl -w
|
||||
# See copyright, etc in below POD section.
|
||||
######################################################################
|
||||
|
||||
use Getopt::Long;
|
||||
use Cwd;
|
||||
use IO::File;
|
||||
use Pod::Usage;
|
||||
use strict;
|
||||
use vars qw ($Debug);
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
our $Opt_Stage = 0;
|
||||
our $Opt_Jobs = calc_jobs();
|
||||
|
||||
autoflush STDOUT 1;
|
||||
autoflush STDERR 1;
|
||||
Getopt::Long::config ("no_auto_abbrev");
|
||||
if (! GetOptions (
|
||||
"debug" => sub { $Debug = 1; },
|
||||
"<>" => sub { die "%Error: Unknown parameter: $_[0]\n"; },
|
||||
"stage=i" => \$Opt_Stage,
|
||||
"j=i" => \$Opt_Jobs,
|
||||
)) {
|
||||
die "%Error: Bad usage, try 'install_test --help'\n";
|
||||
}
|
||||
|
||||
test();
|
||||
exit(0);
|
||||
|
||||
#######################################################################
|
||||
|
||||
sub test {
|
||||
-r "nodist/install_test" or die "%Error: Run from the top of the verilator kit,";
|
||||
|
||||
cleanenv();
|
||||
$ENV{VERILATOR_NO_OPT_BUILD} = 1; # Don't build optimized executables; just slows this down
|
||||
run("make distclean") if -r "Makefile";
|
||||
|
||||
# Try building from a scratch area
|
||||
my $srcdir = getcwd();
|
||||
my $blddir = $srcdir."/test_regress/obj_dir/install_test_bld";
|
||||
my $prefix = $srcdir."/test_regress/obj_dir/install_test_prefix";
|
||||
my $testdirp= $srcdir."/test_regress/obj_dir/install_test_testp";
|
||||
my $testdirn= $srcdir."/test_regress/obj_dir/install_test_testn";
|
||||
|
||||
if ($Opt_Stage <= 0) {
|
||||
run("/bin/rm -rf $blddir");
|
||||
run("/bin/mkdir -p $blddir");
|
||||
run("cd $blddir && $srcdir/configure --prefix $prefix");
|
||||
run("cd $blddir && make -j $Opt_Jobs");
|
||||
}
|
||||
|
||||
# Install it under the prefix
|
||||
if ($Opt_Stage <= 1) {
|
||||
run("/bin/rm -rf $prefix");
|
||||
run("/bin/mkdir -p $prefix");
|
||||
run("cd $blddir && make install");
|
||||
run("test -e $prefix/share/man/man1/verilator.1");
|
||||
run("test -e $prefix/share/verilator/examples/test_c/Makefile");
|
||||
run("test -e $prefix/share/verilator/include/verilated.h");
|
||||
run("test -e $prefix/bin/verilator");
|
||||
run("test -e $prefix/bin/verilator_bin");
|
||||
run("test -e $prefix/bin/verilator_bin_dbg");
|
||||
run("test -e $prefix/bin/verilator_profcfunc");
|
||||
}
|
||||
|
||||
# Run a test using just the path
|
||||
if ($Opt_Stage <= 2) {
|
||||
my $dir = $testdirp;
|
||||
run("/bin/rm -rf $dir");
|
||||
run("/bin/mkdir -p $dir");
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
write_verilog($dir);
|
||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH verilator --cc foo.v --exe foo.cpp");
|
||||
run("cd $dir/obj_dir && PATH=$bin1:$bin2:\$PATH make -f Vfoo.mk");
|
||||
run("cd $dir && PATH=$bin1:$bin2:\$PATH obj_dir/Vfoo");
|
||||
}
|
||||
|
||||
# Run a test using exact path to binary
|
||||
if ($Opt_Stage <= 3) {
|
||||
my $dir = $testdirn;
|
||||
run("/bin/rm -rf $dir");
|
||||
run("/bin/mkdir -p $dir");
|
||||
write_verilog($dir);
|
||||
my $bin1 = $prefix."/bin";
|
||||
my $bin2 = $prefix."/share/bin";
|
||||
run("cd $dir && $bin1/verilator --cc foo.v --exe foo.cpp");
|
||||
run("cd $dir/obj_dir && make -f Vfoo.mk");
|
||||
run("cd $dir/obj_dir && ./Vfoo");
|
||||
}
|
||||
}
|
||||
|
||||
sub write_verilog {
|
||||
my $dir = shift;
|
||||
IO::File->new(">$dir/foo.v")->print('module t; initial begin $display("HELLO WORLD"); $finish; end endmodule'."\n");
|
||||
my $fh = IO::File->new(">$dir/foo.cpp");
|
||||
$fh->print('#include "Vfoo.h"' ,"\n");
|
||||
$fh->print('unsigned int main_time = 0;' ,"\n");
|
||||
$fh->print('double sc_time_stamp () {' ,"\n");
|
||||
$fh->print(' return main_time;' ,"\n");
|
||||
$fh->print('}' ,"\n");
|
||||
$fh->print('int main() {' ,"\n");
|
||||
$fh->print(' Vfoo *top = new Vfoo;' ,"\n");
|
||||
$fh->print(' while (!Verilated::gotFinish()) {',"\n");
|
||||
$fh->print(' top->eval();' ,"\n");
|
||||
$fh->print(' main_time++;' ,"\n");
|
||||
$fh->print(' }' ,"\n");
|
||||
$fh->print(' top->final();' ,"\n");
|
||||
$fh->print('}' ,"\n");
|
||||
}
|
||||
|
||||
sub cleanenv {
|
||||
foreach my $var (keys %ENV) {
|
||||
if ($var eq "VERILATOR_ROOT"
|
||||
|| $var eq "VERILATOR_INCLUDE") {
|
||||
print "unset $var # Was '$ENV{$var}'\n";
|
||||
delete $ENV{$var}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
|
||||
sub calc_jobs {
|
||||
my $ok = eval "
|
||||
use Unix::Processors;
|
||||
return Unix::Processors->new->max_online;
|
||||
";
|
||||
$ok && !$@ or return 1;
|
||||
print "driver.pl: Found $ok cores, using -j ",$ok+1,"\n" if $Debug;
|
||||
return $ok + 1;
|
||||
}
|
||||
|
||||
sub run {
|
||||
# Run a system command, check errors
|
||||
my $command = shift;
|
||||
print "\t$command\n";
|
||||
system "$command";
|
||||
my $status = $?;
|
||||
($status == 0) or die "%Error: Command Failed $command, $status, stopped";
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
install_test - Build and install Verilator several ways
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
install_test
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
install_test performs several make-and-install iterations to verify the
|
||||
kit. It isn't part of the normal "make test" due to the number of builds
|
||||
required.
|
||||
|
||||
=head1 ARGUMENTS
|
||||
|
||||
=over 4
|
||||
|
||||
=item --help
|
||||
|
||||
Displays this message and program version and exits.
|
||||
|
||||
=item -j I<jobs>
|
||||
|
||||
Specify make -j flag. Defaults to number of cores + 1 if Perl's
|
||||
Unix::Processors is installed, else 1.
|
||||
|
||||
=item -stage I<stage>
|
||||
|
||||
Runs a specific test stage (see the script).
|
||||
|
||||
=back
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2009-2017 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "cd .. ; nodist/install_test "
|
||||
### End:
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/perl -w
|
||||
# See copyright, etc in below POD section.
|
||||
######################################################################
|
||||
|
||||
require 5.006_001;
|
||||
use strict;
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
eval `modulecmd perl add axiom-athdl`;
|
||||
exec('atsim',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
invoke_atsim - Invoke tool under "modules" command
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
invoke_atsim {ncv arguments}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2017 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "./invoke_atsim -help"
|
||||
### End:
|
||||
+2
-14
@@ -8,21 +8,9 @@ use strict;
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','cadence_verif');
|
||||
eval `modulecmd perl add cds-ius`;
|
||||
exec('iccr',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
# Modules package
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "/sicortex/$ENV{DIRPROJECT_ARCH}/lib/Modules/default/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
@@ -40,7 +28,7 @@ invoke_iccr - Invoke tool under "modules" command
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2007-2009 by Wilson Snyder. This package is free software; you
|
||||
Copyright 2007-2017 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
+2
-14
@@ -8,21 +8,9 @@ use strict;
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
delete $ENV{MODULE_VERSION};
|
||||
_setup_modules();
|
||||
module('add','cadence_verif');
|
||||
eval `modulecmd perl add cds-ius`;
|
||||
exec('ncverilog',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
# Modules package
|
||||
|
||||
sub _setup_modules {
|
||||
# Load the 'module' command into the environment
|
||||
my $init = "/sicortex/$ENV{DIRPROJECT_ARCH}/lib/Modules/default/init/perl";
|
||||
(-f $init) or die "%Error: Script not found: $init,";
|
||||
require $init;
|
||||
}
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
@@ -40,7 +28,7 @@ invoke_ncverilog - Invoke tool under "modules" command
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. This package is free software; you
|
||||
Copyright 2005-2017 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
Executable
+47
@@ -0,0 +1,47 @@
|
||||
#!/usr/bin/perl -w
|
||||
# See copyright, etc in below POD section.
|
||||
######################################################################
|
||||
|
||||
require 5.006_001;
|
||||
use strict;
|
||||
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
eval `modulecmd perl add synopsys-sim`;
|
||||
exec('vcs',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
__END__
|
||||
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
invoke_vcs - Invoke tool under "modules" command
|
||||
|
||||
=head1 SYNOPSIS
|
||||
|
||||
invoke_vcs {ncv arguments}
|
||||
|
||||
=head1 DESCRIPTION
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2017 by Wilson Snyder. This package is free software; you
|
||||
can redistribute it and/or modify it under the terms of either the GNU
|
||||
Lesser General Public License Version 3 or the Perl Artistic License
|
||||
Version 2.0.
|
||||
|
||||
=head1 AUTHORS
|
||||
|
||||
Wilson Snyder <[email protected]>
|
||||
|
||||
=head1 SEE ALSO
|
||||
|
||||
=cut
|
||||
|
||||
######################################################################
|
||||
### Local Variables:
|
||||
### compile-command: "./invoke_vcs -help"
|
||||
### End:
|
||||
@@ -1,4 +1,4 @@
|
||||
export GLIBCPP_FORCE_NEW=1
|
||||
compile with -DVL_LEAK_CHECKS
|
||||
valgrind --tool=memcheck --leak-check=yes /home/wsnyder/src/verilator/v4/verilator/verilator_bin_dbg -MMD --bin /home/wsnyder/src/verilator/v4/verilator/verilator_bin_dbg --cc -f /home/wsnyder/src/verilator/v4/verilator/test_c/../test_v/input.vc top.v --no-skip-identical 2>&1 | tee ~/d/aa
|
||||
valgrind --tool=memcheck --leak-check=yes /home/wsnyder/src/verilator/v4/verilator/verilator_bin_dbg -MMD --bin /home/wsnyder/src/verilator/v4/verilator/verilator_bin_dbg --cc /home/wsnyder/src/verilator/v4/verilator/test_regress/t/t_case_huge.v --no-skip-identical -I/home/wsnyder/src/verilator/v4/verilator/test_regress/t 2>&1 | tee ~/d/aa
|
||||
valgrind --tool=memcheck --leak-check=yes $VERILATOR_ROOT/verilator_bin_dbg -MMD --bin $VERILATOR_ROOT/verilator_bin_dbg --cc -f $VERILATOR_ROOT/test_c/../test_v/input.vc top.v --no-skip-identical 2>&1 | tee ~/d/aa
|
||||
valgrind --tool=memcheck --leak-check=yes $VERILATOR_ROOT/verilator_bin_dbg -MMD --bin $VERILATOR_ROOT/verilator_bin_dbg --cc $VERILATOR_ROOT/test_regress/t/t_case_huge.v --no-skip-identical -I$VERILATOR_ROOT/test_regress/t 2>&1 | tee ~/d/aa
|
||||
|
||||
@@ -40,7 +40,7 @@ print '(query-replace-regexp "(\\([0-9a-z_]+\\))" "\\1" nil nil nil)',"\n";
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
sub usage {
|
||||
pod2usage(-verbose=>2, -exitval => 2);
|
||||
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
@@ -256,7 +256,7 @@ sub gentree {
|
||||
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
|
||||
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
|
||||
'UNARYMIN' => sub { p " -";p1; },
|
||||
'NEGATE' => sub { p " -";p1; },
|
||||
'VAR' => sub { p_var(); },
|
||||
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'VARREF' => sub { a1; },
|
||||
@@ -331,7 +331,7 @@ Displays this message and program version and exits.
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2005-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
Copyright 2005-2017 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
|
||||
|
||||
-197
@@ -1,197 +0,0 @@
|
||||
\input texinfo @c -*-texinfo-*-
|
||||
@c %**start of header
|
||||
@setfilename readme.info
|
||||
@settitle Verilator Installation
|
||||
@c %**end of header
|
||||
|
||||
@c DESCRIPTION: TexInfo: DOCUMENT source run through texinfo to produce README file
|
||||
@c Use 'make README' to produce the output file
|
||||
@c Before release, run C-u C-c C-u C-a (texinfo-all-menus-update)
|
||||
|
||||
@node Top, Copyright, (dir), (dir)
|
||||
@chapter Verilator
|
||||
|
||||
This is the Verilator Package.
|
||||
|
||||
@menu
|
||||
* Copyright::
|
||||
* Description::
|
||||
* Obtaining Distribution::
|
||||
* Directory Structure::
|
||||
* Supported Systems::
|
||||
* Installation::
|
||||
* Limitations::
|
||||
@end menu
|
||||
|
||||
@node Copyright, Description, Top, Top
|
||||
@section Copyright
|
||||
|
||||
This package is Copyright 2003-2009 by Wilson Snyder @email{wsnyder@@wsnyder.org}.
|
||||
|
||||
Verilator is free software; you can redistribute it and/or modify it
|
||||
under the terms of either the GNU General Public License Version 3 or
|
||||
the Perl Artistic License Version 2.0. (See the documentation for
|
||||
more details.)
|
||||
|
||||
This program is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
General Public License for more details.
|
||||
|
||||
@node Description, Obtaining Distribution, Copyright, Top
|
||||
@section Description
|
||||
|
||||
Verilator converts synthesizable (not behavioral) Verilog code into C++ or
|
||||
SystemC code. It is not a complete simulator, just a translator.
|
||||
|
||||
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
|
||||
reads the specified Verilog code, lints it, and optionally adds coverage
|
||||
code. For C++ format, it outputs .cpp and .h files. For SystemC format,
|
||||
it outputs .sp files for the SystemPerl preprocessor available at
|
||||
http://www.veripool.org.
|
||||
|
||||
The resulting files are then compiled with C++. The user writes a little
|
||||
C++ wrapper file, which instantiates the top level module. This is
|
||||
compiled in C++, and linked with the Verilated files.
|
||||
|
||||
The resulting executable will perform the actual simulation.
|
||||
|
||||
@node Obtaining Distribution, Directory Structure, Description, Top
|
||||
@section Obtaining Distribution
|
||||
|
||||
The latest version is available at
|
||||
@uref{http://www.veripool.org/verilator}
|
||||
|
||||
Download the latest package from that site, and decompress.
|
||||
@samp{tar xvzf verilator_version.tgz}
|
||||
|
||||
@node Directory Structure, Supported Systems, Obtaining Distribution, Top
|
||||
@section Directory Structure
|
||||
|
||||
The directories after de-taring are as follows:
|
||||
|
||||
@itemize @bullet
|
||||
@item bin/verilator => Compiler Wrapper invoked on user Verilog code
|
||||
@item include/ => Files that should be in your -I compiler path
|
||||
@item include/verilated.cpp => Global routines to link into your simulator
|
||||
@item include/verilated.h => Global headers
|
||||
@item include/verilated.v => Stub defines for linting
|
||||
@item include/verilated.mk => Common makefile
|
||||
@item src/ => Translator source code
|
||||
@item test_v => Example Verilog code for other test dirs
|
||||
@item test_c => Example Verilog->C++ conversion
|
||||
@item test_sc => Example Verilog->SystemC conversion
|
||||
@item test_sp => Example Verilog->SystemPerl conversion
|
||||
@item test_vcs => Example Verilog->VCS conversion (test the test)
|
||||
@item test_verilated => Internal tests
|
||||
@item test_regress => Internal tests
|
||||
@end itemize
|
||||
|
||||
@node Supported Systems, Installation, Directory Structure, Top
|
||||
@section Supported Systems
|
||||
|
||||
This version of verilator has been built and tested on:
|
||||
|
||||
@itemize @bullet
|
||||
@item SuSE AMD64 i686-linux-2.6.5
|
||||
@end itemize
|
||||
|
||||
Other users report success with Redhat Linux 2.4, Windows under
|
||||
Cygwin, HPUX and Solaris. It should run with minor porting on any
|
||||
Unix system.
|
||||
|
||||
@node Installation, Limitations, Supported Systems, Top
|
||||
@section Installation
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
If you will be using SystemC (vs straight C++ output), download
|
||||
SystemC 2.0.1 from @url{http://www.systemc.org}. Follow their
|
||||
installation instructions. As described in the System-Perl README,
|
||||
you will need to set SYSTEMC and/or SYSTEMC_KIT to point to this
|
||||
download. Also, set SYSTEMC_ARCH to the architecture name you used
|
||||
with SystemC, generally 'linux' or 'cygwin'.
|
||||
|
||||
@item
|
||||
If you will be using SystemC, download and install Verilog-Perl,
|
||||
@url{http://search.cpan.org/search?module=Verilog::Language}.
|
||||
|
||||
@item
|
||||
If you will be using SystemC, download and install System-Perl,
|
||||
@url{http://search.cpan.org/search?module=SystemC::Netlist}. Note
|
||||
you'll need to set a @samp{SYSTEMPERL} environment variable to point
|
||||
to the downloaded kit. Optionally also set @samp{SYSTEMPERL_INCLUDE}
|
||||
to point to the installed headers.
|
||||
|
||||
@item
|
||||
@code{cd} to the Verilator directory containing this README.
|
||||
|
||||
@item
|
||||
Type @samp{./configure} to configure Verilator for your system.
|
||||
|
||||
If you are configuring Verilator to be part of a RPM or other
|
||||
distribution package system, you may want to use the --enable-defenv
|
||||
configure flag. This will take the current value of VERILATOR_ROOT,
|
||||
SYSTEMC, SYSTEMC_ARCH, SYSTEMPERL, and SYSTEMPERL_INCLUDE and build
|
||||
them as defaults into the executable.
|
||||
|
||||
@item
|
||||
Type @samp{make} to compile Verilator.
|
||||
|
||||
On Cygwin (Windows) you may get a error about libperl.a not being
|
||||
found. You need to copy your perl libraries as follows.
|
||||
|
||||
@enumerate
|
||||
@item
|
||||
Type @samp{perl -MExtUtils::Embed -e ldopts}
|
||||
@item
|
||||
It will show a directory name ending in /CORE. cd to that directory.
|
||||
@item
|
||||
@samp{cp libperl5_6_1.a libperl.a}
|
||||
@item
|
||||
@samp{cp libperl5_6_1.dll libperl.dll}
|
||||
@item
|
||||
@samp{cp libperl5_6_1.def libperl.def}
|
||||
@end enumerate
|
||||
|
||||
@item
|
||||
Type @samp{make test} to check the compilation.
|
||||
|
||||
You may get a error about the Bit::Vector perl package. You will need to install
|
||||
it if you want the tests to pass. (Try @samp{make test_c} for a smaller test that
|
||||
doesn't require it.)
|
||||
|
||||
You may get a error about a typedef conflict for uint32_t. Edit verilated.h to change
|
||||
the typedef to work, probably to @samp{typedef unsigned long uint32_t;}.
|
||||
|
||||
If you get warnings, you might want to edit @samp{include/verilated.mk} to delete the
|
||||
lines that define VK_CPPFLAGS_WALL.
|
||||
|
||||
@item
|
||||
|
||||
There is no installation at present; this package runs from the
|
||||
distribution directory. Programs should set the environment variable
|
||||
VERILATOR_ROOT to point to this distribution, then execute
|
||||
$VERILATOR_ROOT/bin/verilator, which will find the path to all needed
|
||||
files.
|
||||
|
||||
Verilator assumes you did a make in the SystemC kit directory. If not, you will need
|
||||
to populate @samp{$SYSTEMC/include} and @samp{$SYSTEMC/lib-linux} appropriately.
|
||||
|
||||
If you will be modifying Verilator, you will probably want a second
|
||||
stable copy of this kit for others to use while you experiment.
|
||||
|
||||
@item
|
||||
Detailed documentation and the man page can be seen by running:
|
||||
|
||||
bin/verilator --help
|
||||
|
||||
or reading verilator.txt in the same directory as this README.
|
||||
|
||||
@end enumerate
|
||||
|
||||
@node Limitations, , Installation, Top
|
||||
@section Limitations
|
||||
|
||||
See verilator.txt (or execute @samp{bin/verilator --help}) for limitations.
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
# DESCRIPTION: Verilator: GDB startup file with useful defines
|
||||
#
|
||||
# Copyright 2012-2017 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.
|
||||
|
||||
define pn
|
||||
call $arg0->dumpGdb()
|
||||
end
|
||||
document pn
|
||||
Verilator: Print single AstNode NODEP
|
||||
end
|
||||
|
||||
define pnt
|
||||
call $arg0->dumpTreeGdb()
|
||||
end
|
||||
document pnt
|
||||
Verilator: Print AstNode NODEP's tree
|
||||
end
|
||||
|
||||
define dtf
|
||||
call AstNode::dumpTreeFileGdb(0)
|
||||
end
|
||||
document dtf
|
||||
Verilator: Dump AstNode tree to file
|
||||
end
|
||||
|
||||
define watchedit
|
||||
watch AstNode::s_editCntGbl==$arg0
|
||||
end
|
||||
document watchedit
|
||||
Verilator: Create watch on where a edit number is made
|
||||
end
|
||||
@@ -1,70 +0,0 @@
|
||||
=pod
|
||||
|
||||
=head1 NAME
|
||||
|
||||
Verilator Source Code Notes
|
||||
|
||||
=head1 INTRODUCTION
|
||||
|
||||
See also the Verilator internals presentation at http://www.veripool.org.
|
||||
|
||||
=head1 VISITOR FUNCTIONS
|
||||
|
||||
=head2 Passing Variables
|
||||
|
||||
There's three ways data is passed between visitor functions.
|
||||
|
||||
1. A visitor-class member variable. This is generally for passing "parent"
|
||||
information down to children. m_modp is a common example. It's set to
|
||||
NULL in the constructor, where that node (AstModule visitor) sets it, then
|
||||
the children are iterated, then it's cleared. Children under an AstModule
|
||||
will see it set, while nodes elsewhere will see it clear. If there can be
|
||||
nested items (for example an AstFor under an AstFor) the variable needs to
|
||||
be save-set-restored in the AstFor visitor, otherwise exiting the lower for
|
||||
will loose the upper for's setting.
|
||||
|
||||
2. User() attributes. Each node has 4 ->user() number or ->userp() pointer
|
||||
utility values (a common technique lifted from graph traversal packages).
|
||||
A visitor first clears the one it wants to use by calling
|
||||
AstNode::user#ClearTree(), then it can mark any node's user() with whatever
|
||||
data it wants. Readers just call nodep->user(), but may need to cast
|
||||
appropriately, so you'll often see nodep->userp()->castSOMETYPE(). At the
|
||||
top of each visitor are comments describing how the user() stuff applies to
|
||||
that visitor class. For example:
|
||||
|
||||
// NODE STATE
|
||||
// Cleared entire netlist
|
||||
// AstModule::user1p() // bool. True to inline this module
|
||||
|
||||
This says that at the AstNetlist user1ClearTree() is called. Each
|
||||
AstModule's is user1() is used to indicate if we're going to inline it.
|
||||
|
||||
These comments are important to make sure a user#() on a given AstNode type
|
||||
is never being used for two different purposes.
|
||||
|
||||
Note that calling user#ClearTree is fast, it doesn't walk the tree, so it's
|
||||
ok to call fairly often. For example, it's commonly called on every
|
||||
module.
|
||||
|
||||
3. Parameters can be passed between the visitors in close to the "normal"
|
||||
function caller to callee way. This is the second "vup" parameter that is
|
||||
ignored on most of the visitor functions. V3Width does this, but it proved
|
||||
more messy than the above and is deprecated. (V3Width was nearly the first
|
||||
module written. Someday this scheme may be removed, as it slows the
|
||||
program down to have to pass vup everywhere.)
|
||||
|
||||
=head1 DEBUGGING WITH GDB
|
||||
|
||||
The test_regress/driver.pl script accepts --gdb to start Verilator under
|
||||
gdb.
|
||||
|
||||
To break at a specific edit number which changed a node (presumably to find
|
||||
what made a <e####> line in the tree dumps):
|
||||
|
||||
watch AstNode::s_editCntGbl==####
|
||||
|
||||
=head1 DISTRIBUTION
|
||||
|
||||
Copyright 2008-2009 by Wilson Snyder. Verilator is free software; you can
|
||||
redistribute it and/or modify it under the terms of either the GNU Lesser
|
||||
General Public License Version 3 or the Perl Artistic License Version 2.0.
|
||||
+29
-28
@@ -7,7 +7,7 @@
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2017 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.
|
||||
@@ -24,6 +24,7 @@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
PERL = @PERL@
|
||||
EXEEXT = @EXEEXT@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
@@ -32,22 +33,11 @@ default: dbg opt
|
||||
debug: dbg
|
||||
optimize: opt
|
||||
|
||||
ifeq ($(OBJCACHE_HOSTS),)
|
||||
ifneq ($(SLCHOOSED_HOST),)
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1)
|
||||
export OBJCACHE_HOSTS := $(shell rschedule --no-allow-reserved --similar hostnames)
|
||||
endif
|
||||
endif
|
||||
ifneq ($(words $(CURDIR)),1)
|
||||
$(error Unsupported: GNU Make cannot build in directories containing spaces, build elsewhere: '$(CURDIR)')
|
||||
endif
|
||||
|
||||
ifeq ($(OBJCACHE_HOSTS),)
|
||||
export OBJCACHE :=
|
||||
else
|
||||
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
|
||||
export OBJCACHE := @objcache --read --write
|
||||
endif
|
||||
|
||||
UNDER_GIT = $(wildcard ../.git/logs/HEAD)
|
||||
UNDER_GIT = $(wildcard ${srcdir}/../.git/logs/HEAD)
|
||||
|
||||
#*********************************************************************
|
||||
|
||||
@@ -56,31 +46,39 @@ obj_opt:
|
||||
obj_dbg:
|
||||
mkdir $@
|
||||
|
||||
.PHONY: ../verilator_bin ../verilator_bin_dbg
|
||||
.SUFFIXES:
|
||||
|
||||
.PHONY: ../verilator_bin ../verilator_bin_dbg ../verilator_coverage_bin_dbg
|
||||
|
||||
opt: ../verilator_bin
|
||||
ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build
|
||||
../verilator_bin: ../verilator_bin_dbg
|
||||
cp -p $< $@
|
||||
@-cp -p $<.exe $@.exe
|
||||
-rm -rf $@ $@.exe
|
||||
-cp -p $<$(EXEEXT) $@$(EXEEXT)
|
||||
else
|
||||
../verilator_bin: obj_opt prefiles
|
||||
cd obj_opt && $(MAKE) TGT=../$@ -f ../Makefile_obj serial
|
||||
cd obj_opt && $(MAKE) $(OBJCACHE_JOBS) TGT=../$@ -f ../Makefile_obj
|
||||
cd obj_opt && $(MAKE) -j 1 TGT=../$@ -f ../Makefile_obj serial
|
||||
cd obj_opt && $(MAKE) TGT=../$@ -f ../Makefile_obj
|
||||
endif
|
||||
|
||||
dbg: ../verilator_bin_dbg
|
||||
dbg: ../verilator_bin_dbg ../verilator_coverage_bin_dbg
|
||||
../verilator_bin_dbg: obj_dbg prefiles
|
||||
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
|
||||
cd obj_dbg && $(MAKE) $(OBJCACHE_JOBS) TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
|
||||
cd obj_dbg && $(MAKE) -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
|
||||
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
|
||||
|
||||
../verilator_coverage_bin_dbg: obj_dbg prefiles
|
||||
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
|
||||
cd obj_dbg && $(MAKE) TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
|
||||
|
||||
prefiles::
|
||||
|
||||
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
|
||||
prefiles:: config_rev.h
|
||||
# This output goes into srcdir, as we need to distribute it as part of the kit.
|
||||
config_rev.h: config_rev.pl ../.git/logs/HEAD
|
||||
$(PERL) config_rev.pl . >$@
|
||||
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
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
else
|
||||
config_rev.h: ${srcdir}/config_rev.pl
|
||||
$(PERL) ${srcdir}/config_rev.pl ${srcdir} >$@
|
||||
endif
|
||||
|
||||
maintainer-copy::
|
||||
@@ -92,3 +90,6 @@ clean mostlyclean distclean maintainer-clean::
|
||||
|
||||
distclean maintainer-clean::
|
||||
-rm -f Makefile Makefile_obj config_build.h
|
||||
|
||||
maintainer-clean::
|
||||
-rm -f config_rev.h
|
||||
|
||||
+93
-49
@@ -7,7 +7,7 @@
|
||||
#
|
||||
#*****************************************************************************
|
||||
#
|
||||
# Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
# Copyright 2003-2017 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.
|
||||
@@ -21,8 +21,22 @@
|
||||
|
||||
#### Start of system configuration section. ####
|
||||
|
||||
srcdir = ..
|
||||
incdir = ../../include
|
||||
# Unfortunately configure uses relative paths, and this makefile is called
|
||||
# from a level lower, so we need to move up if it's relative, not if absolute.
|
||||
config_srcdir = @srcdir@
|
||||
ifeq ($(config_srcdir),.)
|
||||
srcdir = ..
|
||||
else # Run an experiment
|
||||
ifeq ($(wildcard $(config_srcdir)/../Makefile_obj.in),)
|
||||
srcdir = $(config_srcdir)
|
||||
else
|
||||
srcdir = $(config_srcdir)/..
|
||||
endif
|
||||
endif
|
||||
|
||||
incdir = $(srcdir)/../include
|
||||
# Bldsrc may differ from srcdir if configure wan't run from the kit top
|
||||
bldsrc = ..
|
||||
|
||||
# Programs
|
||||
CC = @CC@
|
||||
@@ -43,19 +57,25 @@ datarootdir = @datarootdir@
|
||||
pkgdatadir = @pkgdatadir@
|
||||
|
||||
# Compile options
|
||||
CFG_WITH_CCWARN = @CFG_WITH_CCWARN@
|
||||
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
|
||||
CPPFLAGSNOWALL += @CPPFLAGS@
|
||||
CPPFLAGS += @CPPFLAGS@
|
||||
LDFLAGS += @LDFLAGS@
|
||||
EXEEXT = @EXEEXT@
|
||||
CFG_CXXFLAGS_SRC = @CFG_CXXFLAGS_SRC@
|
||||
CFG_CXXFLAGS_PARSER = @CFG_CXXFLAGS_PARSER@
|
||||
# Compiler flags that turn on extra warnings
|
||||
CFG_CXXFLAGS_WEXTRA = @CFG_CXXFLAGS_WEXTRA@
|
||||
|
||||
#### End of system configuration section. ####
|
||||
|
||||
VPATH += . $(srcdir)
|
||||
VPATH += . $(bldsrc) $(srcdir)
|
||||
TGT = ../../verilator_bin
|
||||
|
||||
#################
|
||||
ifeq ($(VL_DEBUG),)
|
||||
# Optimize
|
||||
COPT = -O
|
||||
COPT = -O2
|
||||
else
|
||||
# Debug
|
||||
COPT = -ggdb -DVL_DEBUG
|
||||
@@ -68,33 +88,32 @@ endif
|
||||
#LIBS += -ldl
|
||||
#CCMALLOC = /usr/local/lib/ccmalloc-gcc.o -lccmalloc -ldl
|
||||
|
||||
LIBS = -lm -lfl
|
||||
# -lfl not needed as Flex invoked with %nowrap option
|
||||
# -lstdc++ needed for clang, believed harmless with gcc
|
||||
LIBS = -lm -lstdc++
|
||||
|
||||
CPPFLAGSNOWALL += -MMD
|
||||
CPPFLAGSNOWALL += -I. -I$(srcdir) -I$(incdir)
|
||||
CPPFLAGSNOWALL += -DYYDEBUG # Required to get nice error messages
|
||||
#CPPFLAGSNOWALL += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
CPPFLAGSNOWALL += $(COPT)
|
||||
CPPFLAGS = $(CPPFLAGSNOWALL)
|
||||
ifeq ($(VERILATOR_AUTHOR_SITE),1) # Local... Else don't burden users
|
||||
CPPFLAGSNOWALL += -MP # Only works on recent GCC versions
|
||||
CPPFLAGS += -W -Wall -Wno-unused-parameter -Wno-char-subscripts -Werror
|
||||
CPPFLAGS += -MMD
|
||||
CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir)
|
||||
CPPFLAGS += -DYYDEBUG # Required to get nice error messages
|
||||
#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool
|
||||
CPPFLAGS += $(COPT)
|
||||
CPPFLAGS += -MP # Only works on recent GCC versions
|
||||
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
|
||||
CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror
|
||||
#CPPFLAGS += -pedantic-errors
|
||||
else
|
||||
CPPFLAGS += $(CFG_CXXFLAGS_SRC)
|
||||
endif
|
||||
|
||||
ifneq ($(SYSTEMPERL),) # Intuit SYSTEMPERL_INCLUDE as it's new
|
||||
SYSTEMPERL_INCLUDE ?= $(SYSTEMPERL)/src
|
||||
#else if set, leave as-is.
|
||||
#else if SYSTEMPERL="" don't set _INCLUDE so source will figure it out
|
||||
endif
|
||||
CPPFLAGSWALL = $(CPPFLAGS)
|
||||
CPPFLAGSPARSER = $(CPPFLAGS) $(CFG_CXXFLAGS_PARSER)
|
||||
|
||||
# Allow RPM builds to specify hardcoded data directories
|
||||
# To do this:
|
||||
ifeq ($(CFG_WITH_DEFENV),yes)
|
||||
CPPFLAGS += -DDEFENV_SYSTEMC=\"$(SYSTEMC)\"
|
||||
CPPFLAGS += -DDEFENV_SYSTEMC_ARCH=\"$(SYSTEMC_ARCH)\"
|
||||
CPPFLAGS += -DDEFENV_SYSTEMPERL=\"$(SYSTEMPERL)\"
|
||||
CPPFLAGS += -DDEFENV_SYSTEMPERL_INCLUDE=\"$(SYSTEMPERL_INCLUDE)\"
|
||||
CPPFLAGS += -DDEFENV_SYSTEMC_INCLUDE=\"$(SYSTEMC_INCLUDE)\"
|
||||
CPPFLAGS += -DDEFENV_SYSTEMC_LIBDIR=\"$(SYSTEMC_LIBDIR)\"
|
||||
ifeq ($(VERILATOR_ROOT),) # Use what we're given, or intuit
|
||||
CPPFLAGS += -DDEFENV_VERILATOR_ROOT=\"$(pkgdatadir)\"
|
||||
else
|
||||
@@ -106,6 +125,8 @@ HEADERS = $(wildcard V*.h v*.h)
|
||||
|
||||
ASTGEN = $(srcdir)/astgen
|
||||
BISONPRE = $(srcdir)/bisonpre
|
||||
FLEXFIX = $(srcdir)/flexfix
|
||||
VLCOVGEN = $(srcdir)/vlcovgen
|
||||
|
||||
######################################################################
|
||||
#### Top level
|
||||
@@ -139,13 +160,16 @@ RAW_OBJS = \
|
||||
V3Begin.o \
|
||||
V3Branch.o \
|
||||
V3Broken.o \
|
||||
V3CCtors.o \
|
||||
V3Case.o \
|
||||
V3Cast.o \
|
||||
V3Cdc.o \
|
||||
V3Changed.o \
|
||||
V3Clean.o \
|
||||
V3ClkGater.o \
|
||||
V3Clock.o \
|
||||
V3Combine.o \
|
||||
V3Config.o \
|
||||
V3Const__gen.o \
|
||||
V3Coverage.o \
|
||||
V3CoverageJoin.o \
|
||||
@@ -159,9 +183,11 @@ RAW_OBJS = \
|
||||
V3EmitCSyms.o \
|
||||
V3EmitMk.o \
|
||||
V3EmitV.o \
|
||||
V3EmitXml.o \
|
||||
V3Error.o \
|
||||
V3Expand.o \
|
||||
V3File.o \
|
||||
V3FileLine.o \
|
||||
V3Gate.o \
|
||||
V3GenClk.o \
|
||||
V3Graph.o \
|
||||
@@ -174,11 +200,11 @@ RAW_OBJS = \
|
||||
V3Inst.o \
|
||||
V3Life.o \
|
||||
V3LifePost.o \
|
||||
V3Link.o \
|
||||
V3LinkCells.o \
|
||||
V3LinkDot.o \
|
||||
V3LinkLevel.o \
|
||||
V3LinkJump.o \
|
||||
V3LinkLValue.o \
|
||||
V3LinkLevel.o \
|
||||
V3LinkParse.o \
|
||||
V3LinkResolve.o \
|
||||
V3Localize.o \
|
||||
@@ -186,50 +212,57 @@ RAW_OBJS = \
|
||||
V3Number.o \
|
||||
V3Options.o \
|
||||
V3Order.o \
|
||||
V3Os.o \
|
||||
V3Param.o \
|
||||
V3PreShell.o \
|
||||
V3Premit.o \
|
||||
V3Scope.o \
|
||||
V3Signed.o \
|
||||
V3Slice.o \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
V3Stats.o \
|
||||
V3StatsReport.o \
|
||||
V3String.o \
|
||||
V3Subst.o \
|
||||
V3Table.o \
|
||||
V3Task.o \
|
||||
V3Trace.o \
|
||||
V3TraceDecl.o \
|
||||
V3Tristate.o \
|
||||
V3Undriven.o \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3Width.o \
|
||||
V3WidthSel.o \
|
||||
|
||||
# Non-concatable
|
||||
OBJS += \
|
||||
V3Parse.o \
|
||||
NC_OBJS += \
|
||||
V3ParseImp.o \
|
||||
V3ParseGrammar.o \
|
||||
V3ParseLex.o \
|
||||
V3PreProc.o \
|
||||
V3Read.o \
|
||||
|
||||
# verilator_coverage
|
||||
VLCOV_OBJS = \
|
||||
VlcMain.o \
|
||||
|
||||
#### Linking
|
||||
|
||||
ifeq ($(VL_DEBUG),)
|
||||
# Building with fewer objects to better optimize
|
||||
#OBJS += V3__CONCAT.o
|
||||
OBJS += $(RAW_OBJS)
|
||||
ifeq ($(VL_VLCOV),)
|
||||
PREDEP_H = V3Ast__gen_classes.h
|
||||
OBJS += $(RAW_OBJS) $(NC_OBJS)
|
||||
else
|
||||
OBJS += $(RAW_OBJS)
|
||||
PREDEP_H =
|
||||
OBJS += $(VLCOV_OBJS)
|
||||
endif
|
||||
|
||||
V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
|
||||
$(PERL) $(srcdir)/../bin/verilator_includer $^ > $@
|
||||
|
||||
$(TGT): V3Ast__gen_classes.h $(OBJS)
|
||||
$(TGT): $(PREDEP_H) $(OBJS)
|
||||
@echo " Linking $@..."
|
||||
-rm -rf $@ [email protected]
|
||||
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
|
||||
@-(cp [email protected] $@ || true)
|
||||
# ok if cp failes on linux, it's there to insure executable works on NT
|
||||
|
||||
V3Number_test: V3Number_test.o
|
||||
${LINK} ${LDFLAGS} -o $@ $^ ${LIBS}
|
||||
@@ -240,24 +273,33 @@ V3Number_test: V3Number_test.o
|
||||
$(PERL) $(ASTGEN) -I$(srcdir) $*.cpp
|
||||
|
||||
%.o: %.cpp
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGS} -c $<
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSWALL} -c $<
|
||||
%.o: %.c
|
||||
$(OBJCACHE) ${CC} ${CPPFLAGS} -c $<
|
||||
$(OBJCACHE) ${CC} ${CPPFLAGSWALL} -c $<
|
||||
|
||||
V3Read.o: V3Read.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSNOWALL} -c $<
|
||||
V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSPARSER} -c $<
|
||||
|
||||
V3Parse.o: V3Parse.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSNOWALL} -c $<
|
||||
V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSPARSER} -c $<
|
||||
|
||||
V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSPARSER} -c $<
|
||||
|
||||
V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSNOWALL} -c $<
|
||||
$(OBJCACHE) ${CXX} ${CPPFLAGSPARSER} -c $<
|
||||
|
||||
#### Generated files
|
||||
|
||||
# Target rule called before parallel build to make generated files
|
||||
serial:: V3Ast__gen_classes.h V3ParseBison.c
|
||||
|
||||
serial_vlcov:: vlcovgen.d
|
||||
|
||||
vlcovgen.d: $(VLCOVGEN) $(srcdir)/../include/verilated_cov_key.h
|
||||
$(PERL) $(VLCOVGEN) --srcdir $(srcdir)
|
||||
touch $@
|
||||
|
||||
V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h
|
||||
$(PERL) $(ASTGEN) -I$(srcdir) --classes
|
||||
|
||||
@@ -272,15 +314,17 @@ V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS)
|
||||
${LEX} --version
|
||||
${LEX} ${LFLAGS} -o$@ $<
|
||||
|
||||
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp
|
||||
$(PERL) $(srcdir)/flexfix <$< >$@
|
||||
V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX)
|
||||
$(PERL) $(FLEXFIX) V3Lexer <$< >$@
|
||||
|
||||
V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS)
|
||||
${LEX} --version
|
||||
${LEX} ${LFLAGS} -o$@ $<
|
||||
|
||||
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp
|
||||
$(PERL) $(srcdir)/flexfix <$< >$@
|
||||
V3PreLex.yy.cpp: V3PreLex_pregen.yy.cpp $(FLEXFIX)
|
||||
$(PERL) $(FLEXFIX) V3PreLex <$< >$@
|
||||
|
||||
.SUFFIXES:
|
||||
|
||||
######################################################################
|
||||
######################################################################
|
||||
|
||||
+132
-73
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into sensitivity active domains
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -74,7 +73,7 @@ private:
|
||||
m_scopep->addActivep(nodep);
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
virtual void visit(AstScope* nodep) {
|
||||
m_scopep = nodep;
|
||||
m_iActivep = NULL;
|
||||
m_cActivep = NULL;
|
||||
@@ -82,15 +81,15 @@ private:
|
||||
nodep->iterateChildren(*this);
|
||||
// Don't clear scopep, the namer persists beyond this visit
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep, AstNUser*) {
|
||||
virtual void visit(AstSenTree* nodep) {
|
||||
// Simplify sensitivity list
|
||||
V3Const::constifyTreeExpensive(nodep);
|
||||
V3Const::constifyExpensiveEdit(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
// Empty visitors, speed things up
|
||||
virtual void visit(AstNodeStmt* nodep, AstNUser*) { }
|
||||
virtual void visit(AstNodeStmt* nodep) { }
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
// Default: Just iterate
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
@@ -148,7 +147,11 @@ public:
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ActiveNamer() {}
|
||||
ActiveNamer() {
|
||||
m_scopep = NULL;
|
||||
m_iActivep = NULL;
|
||||
m_cActivep = NULL;
|
||||
}
|
||||
virtual ~ActiveNamer() {}
|
||||
void main(AstScope* nodep) {
|
||||
nodep->accept(*this);
|
||||
@@ -159,27 +162,67 @@ public:
|
||||
// Active AssignDly replacement functions
|
||||
|
||||
class ActiveDlyVisitor : public ActiveBaseVisitor {
|
||||
public:
|
||||
enum CheckType { 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
|
||||
// VISITORS
|
||||
virtual void visit(AstAssignDly* nodep, AstNUser*) {
|
||||
// Convert to a non-delayed assignment
|
||||
UINFO(5," ASSIGNDLY "<<nodep<<endl);
|
||||
nodep->v3warn(COMBDLY,"Delayed assignments (<=) in non-clocked (non flop or latch) blocks should be non-delayed assignments (=).");
|
||||
AstNode* newp = new AstAssign (nodep->fileline(),
|
||||
nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep = NULL;
|
||||
virtual void visit(AstAssignDly* nodep) {
|
||||
if (m_check != CT_SEQ) {
|
||||
// Convert to a non-delayed assignment
|
||||
UINFO(5," ASSIGNDLY "<<nodep<<endl);
|
||||
if (m_check == CT_INITIAL) {
|
||||
nodep->v3warn(INITIALDLY,"Delayed assignments (<=) in initial or final block; 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; suggest blocking assignments (=).");
|
||||
}
|
||||
AstNode* newp = new AstAssign (nodep->fileline(),
|
||||
nodep->lhsp()->unlinkFrBack(),
|
||||
nodep->rhsp()->unlinkFrBack());
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssign* nodep) {
|
||||
if (m_check == CT_SEQ) {
|
||||
AstNode* las = m_assignp;
|
||||
m_assignp = nodep;
|
||||
nodep->lhsp()->iterateAndNext(*this);
|
||||
m_assignp = las;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
AstVar* varp=nodep->varp();
|
||||
if (m_check == CT_SEQ
|
||||
&& m_assignp
|
||||
&& !varp->isUsedLoopIdx() // Ignore loop indicies
|
||||
&& !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_alwaysp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true); // Complain just once for the entire always
|
||||
varp->fileline()->modifyWarnOff(V3ErrorCode::BLKSEQ, true);
|
||||
nodep->v3warn(BLKSEQ,"Blocking assignments (=) in sequential (flop or latch) block; suggest delayed assignments (<=).");
|
||||
}
|
||||
}
|
||||
}
|
||||
// Empty visitors, speed things up
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ActiveDlyVisitor(AstNode* nodep) {
|
||||
ActiveDlyVisitor(AstNode* nodep, CheckType check) {
|
||||
m_alwaysp = nodep;
|
||||
m_check = check;
|
||||
m_assignp = NULL;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~ActiveDlyVisitor() {}
|
||||
@@ -197,12 +240,11 @@ private:
|
||||
// STATE
|
||||
ActiveNamer m_namer; // Tracking of active names
|
||||
AstCFunc* m_scopeFinalp; // Final function for this scope
|
||||
AstAlways* m_alwaysp; // Under always
|
||||
bool m_itemCombo; // Found a SenItem combo
|
||||
bool m_itemSequent; // Found a SenItem sequential
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
virtual void visit(AstScope* nodep) {
|
||||
// Create required actives and add to scope
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
// Clear last scope's names, and collect this scope's existing names
|
||||
@@ -210,48 +252,50 @@ private:
|
||||
m_scopeFinalp = NULL;
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstActive* nodep, AstNUser*) {
|
||||
virtual void visit(AstActive* nodep) {
|
||||
// Actives are being formed, so we can ignore any already made
|
||||
}
|
||||
virtual void visit(AstInitial* nodep, AstNUser*) {
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
// Relink to IACTIVE, unless already under it
|
||||
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, AstNUser*) {
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," ASSIGNW "<<nodep<<endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," ASSIGNW "<<nodep<<endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
||||
virtual void visit(AstCoverToggle* nodep) {
|
||||
// Relink to CACTIVE, unless already under it
|
||||
UINFO(4," COVERTOGGLE "<<nodep<<endl);
|
||||
AstActive* wantactivep = m_namer.getCActive(nodep->fileline());
|
||||
nodep->unlinkFrBack();
|
||||
wantactivep->addStmtsp(nodep);
|
||||
}
|
||||
virtual void visit(AstFinal* nodep, AstNUser*) {
|
||||
virtual void visit(AstFinal* nodep) {
|
||||
// Relink to CFUNC for the final
|
||||
UINFO(4," FINAL "<<nodep<<endl);
|
||||
if (!nodep->bodysp()) { // Empty, Kill it.
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
return;
|
||||
}
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_INITIAL);
|
||||
if (!m_scopeFinalp) {
|
||||
m_scopeFinalp = new AstCFunc(nodep->fileline(), "_final", m_namer.scopep());
|
||||
m_scopeFinalp = new AstCFunc(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"));
|
||||
m_scopeFinalp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
m_scopeFinalp->dontCombine(true);
|
||||
m_scopeFinalp->formCallTree(true);
|
||||
m_scopeFinalp->slow(true);
|
||||
@@ -260,46 +304,36 @@ private:
|
||||
nodep->unlinkFrBack();
|
||||
m_scopeFinalp->addStmtsp(new AstComment(nodep->fileline(), nodep->typeName()));
|
||||
m_scopeFinalp->addStmtsp(nodep->bodysp()->unlinkFrBackWithNext());
|
||||
nodep->deleteTree(); nodep = NULL;
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
void visitAlways(AstNode* nodep, AstSenTree* oldsensesp, VAlwaysKwd kwd) {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALW "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
||||
|
||||
if (!nodep->bodysp()) {
|
||||
// Empty always. Kill it.
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
return;
|
||||
}
|
||||
if (nodep->sensesp()
|
||||
&& nodep->sensesp()->sensesp()
|
||||
&& nodep->sensesp()->sensesp()->castSenItem()
|
||||
&& nodep->sensesp()->sensesp()->castSenItem()->isNever()) {
|
||||
if (oldsensesp
|
||||
&& oldsensesp->sensesp()
|
||||
&& oldsensesp->sensesp()->castSenItem()
|
||||
&& oldsensesp->sensesp()->castSenItem()->isNever()) {
|
||||
// Never executing. Kill it.
|
||||
if (nodep->sensesp()->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
if (oldsensesp->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
return;
|
||||
}
|
||||
|
||||
// Read sensitivitues
|
||||
m_alwaysp = nodep;
|
||||
m_itemCombo = false;
|
||||
m_itemSequent = false;
|
||||
nodep->sensesp()->iterateAndNext(*this);
|
||||
m_alwaysp = NULL;
|
||||
if (oldsensesp) oldsensesp->iterateAndNext(*this);
|
||||
bool combo = m_itemCombo;
|
||||
bool sequent = m_itemSequent;
|
||||
|
||||
if (!combo && !sequent) combo=true; // If no list, Verilog 2000: always @ (*)
|
||||
#ifndef NEW_ORDERING
|
||||
if (combo && sequent) {
|
||||
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity (no edge) sensitive activity list");
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity (no edge) sensitive activity list");
|
||||
}
|
||||
sequent = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
AstActive* wantactivep = NULL;
|
||||
if (combo && !sequent) {
|
||||
@@ -311,15 +345,15 @@ 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) nodep->sensesp()->addSensesp
|
||||
if (combo) oldsensesp->addSensesp
|
||||
(new AstSenItem(nodep->fileline(),AstSenItem::Combo()));
|
||||
#endif
|
||||
wantactivep = m_namer.getActive(nodep->fileline(), nodep->sensesp());
|
||||
wantactivep = m_namer.getActive(nodep->fileline(), oldsensesp);
|
||||
}
|
||||
|
||||
// Delete sensitivity list
|
||||
if (AstNode* oldsense = nodep->sensesp()) {
|
||||
oldsense->unlinkFrBackWithNext()->deleteTree(); oldsense=NULL;
|
||||
if (oldsensesp) {
|
||||
oldsensesp->unlinkFrBackWithNext()->deleteTree(); VL_DANGLING(oldsensesp);
|
||||
}
|
||||
|
||||
// Move node to new active
|
||||
@@ -328,27 +362,52 @@ private:
|
||||
|
||||
// Warn and/or convert any delayed assignments
|
||||
if (combo && !sequent) {
|
||||
ActiveDlyVisitor dlyvisitor (nodep);
|
||||
if (kwd == VAlwaysKwd::ALWAYS_LATCH) {
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_LATCH);
|
||||
} else {
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_COMBO);
|
||||
}
|
||||
}
|
||||
else if (!combo && sequent) {
|
||||
ActiveDlyVisitor dlyvisitor (nodep, ActiveDlyVisitor::CT_SEQ);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep, AstNUser*) {
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALW "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
||||
|
||||
if (!nodep->bodysp()) {
|
||||
// Empty always. Kill it.
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
return;
|
||||
}
|
||||
visitAlways(nodep, nodep->sensesp(), nodep->keyword());
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) {
|
||||
// Move always to appropriate ACTIVE based on its sense list
|
||||
UINFO(4," ALWPub "<<nodep<<endl);
|
||||
//if (debug()>=9) nodep->dumpTree(cout," Alw: ");
|
||||
visitAlways(nodep, nodep->sensesp(), VAlwaysKwd::ALWAYS);
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) {
|
||||
AstSenItem* subitemp = nodep->sensesp();
|
||||
if (subitemp->edgeType() != AstEdgeType::ANYEDGE
|
||||
&& subitemp->edgeType() != AstEdgeType::POSEDGE
|
||||
&& subitemp->edgeType() != AstEdgeType::NEGEDGE) {
|
||||
if (subitemp->edgeType() != AstEdgeType::ET_ANYEDGE
|
||||
&& subitemp->edgeType() != AstEdgeType::ET_POSEDGE
|
||||
&& subitemp->edgeType() != AstEdgeType::ET_NEGEDGE) {
|
||||
nodep->v3fatalSrc("Strange activity type under SenGate");
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep, AstNUser*) {
|
||||
if (nodep->edgeType() == AstEdgeType::ANYEDGE) {
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
if (nodep->edgeType() == AstEdgeType::ET_ANYEDGE) {
|
||||
m_itemCombo = true;
|
||||
// Delete the sensitivity
|
||||
// We'll add it as a generic COMBO SenItem in a moment.
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
} else if (nodep->varrefp()) {
|
||||
// V3LinkResolve should have cleaned most of these up
|
||||
if (nodep->varrefp()->width()>1) nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
||||
if (!nodep->varrefp()->width1()) nodep->v3error("Unsupported: Non-single bit wide signal pos/negedge sensitivity: "
|
||||
<<nodep->varrefp()->prettyName());
|
||||
m_itemSequent = true;
|
||||
nodep->varrefp()->varp()->usedClock(true);
|
||||
@@ -356,17 +415,16 @@ private:
|
||||
}
|
||||
|
||||
// Empty visitors, speed things up
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
|
||||
virtual void visit(AstVarScope* nodep, AstNUser*) {}
|
||||
virtual void visit(AstNodeMath* nodep) {}
|
||||
virtual void visit(AstVarScope* nodep) {}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ActiveVisitor(AstNode* nodep) {
|
||||
explicit ActiveVisitor(AstNetlist* nodep) {
|
||||
m_scopeFinalp = NULL;
|
||||
m_alwaysp = NULL;
|
||||
m_itemCombo = false;
|
||||
m_itemSequent = false;
|
||||
nodep->accept(*this);
|
||||
@@ -380,4 +438,5 @@ public:
|
||||
void V3Active::activeAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ActiveVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("active", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into sensitivity block domains
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+21
-18
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into sensitivity active domains
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -66,29 +65,29 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep, AstNUser*) {
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
m_topscopep = nodep;
|
||||
m_finder.main(m_topscopep);
|
||||
nodep->iterateChildren(*this);
|
||||
m_topscopep = NULL;
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
// Create required actives and add to module
|
||||
// We can start ordering at a module, or a scope
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstActive* nodep, AstNUser*) {
|
||||
virtual void visit(AstActive* nodep) {
|
||||
UINFO(4," ACTIVE "<<nodep<<endl);
|
||||
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
|
||||
AstSenTree* sensesp = nodep->sensesp();
|
||||
if (!sensesp) nodep->v3fatalSrc("NULL");
|
||||
V3Const::constifyTreeExpensive(nodep); // Remove duplicate clocks and such
|
||||
if (sensesp->sensesp()
|
||||
&& sensesp->sensesp()->castSenItem()
|
||||
&& sensesp->sensesp()->castSenItem()->isNever()) {
|
||||
// Never executing. Kill it.
|
||||
if (sensesp->sensesp()->nextp()) nodep->v3fatalSrc("Never senitem should be alone, else the never should be eliminated.");
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
return;
|
||||
}
|
||||
// Copy combo tree to settlement tree with duplicated statements
|
||||
@@ -109,7 +108,7 @@ private:
|
||||
// Move the active's contents to the other active
|
||||
UINFO(4," merge active "<<sensesp<<" into "<<wantp<<endl);
|
||||
if (nodep->sensesStorep()) {
|
||||
if (sensesp != nodep->sensesStorep()) nodep->v3fatalSrc("sensesStore should have been deleted earlier if different\n");
|
||||
if (sensesp != nodep->sensesStorep()) nodep->v3fatalSrc("sensesStore should have been deleted earlier if different");
|
||||
sensesp->unlinkFrBack();
|
||||
// There may be other references to same sense tree,
|
||||
// we'll be removing all references when we get to them,
|
||||
@@ -121,31 +120,34 @@ private:
|
||||
// No need to do statements under it, they're already moved.
|
||||
//nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep, AstNUser*) {
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep, AstNUser*) {
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstFinal* nodep, AstNUser*) {
|
||||
virtual void visit(AstAlwaysPublic* nodep) {
|
||||
nodep->v3fatalSrc("Node should have been under ACTIVE");
|
||||
}
|
||||
virtual void visit(AstFinal* nodep) {
|
||||
nodep->v3fatalSrc("Node should have been deleted");
|
||||
}
|
||||
// Empty visitors, speed things up
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
|
||||
virtual void visit(AstVarScope* nodep, AstNUser*) {}
|
||||
virtual void visit(AstNodeMath* nodep) {}
|
||||
virtual void visit(AstVarScope* nodep) {}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ActiveTopVisitor(AstNetlist* nodep) {
|
||||
explicit ActiveTopVisitor(AstNetlist* nodep) {
|
||||
m_topscopep = NULL;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
@@ -158,4 +160,5 @@ public:
|
||||
void V3ActiveTop::activeTopAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ActiveTopVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("activetop", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into sensitivity block domains
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+125
-88
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Collect and print statistics
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2017 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.
|
||||
@@ -44,7 +43,7 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp; // Last module
|
||||
AstNodeModule* m_modp; // Last module
|
||||
AstBegin* m_beginp; // Last begin
|
||||
V3Double0 m_statAsCover; // Statistic tracking
|
||||
V3Double0 m_statAsPsl; // Statistic tracking
|
||||
@@ -57,47 +56,40 @@ private:
|
||||
+":"+cvtToStr(nodep->fileline()->lineno())
|
||||
+": Assertion failed in %m"
|
||||
+((message != "")?": ":"")+message
|
||||
+"\\n");
|
||||
+"\n");
|
||||
}
|
||||
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
|
||||
nodep->displayType(AstDisplayType::WRITE);
|
||||
nodep->text(assertDisplayMessage(nodep, prefix, nodep->text()));
|
||||
AstNode* timesp = nodep->exprsp(); if (timesp) timesp->unlinkFrBack();
|
||||
timesp = timesp->addNext(new AstTime(nodep->fileline()));
|
||||
nodep->exprsp(timesp);
|
||||
if (!nodep->scopeNamep()
|
||||
&& (nodep->name().find("%m") != string::npos
|
||||
|| nodep->name().find("%M") != string::npos)) {
|
||||
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
nodep->displayType(AstDisplayType::DT_WRITE);
|
||||
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
|
||||
// cppcheck-suppress nullPointer
|
||||
AstNode* timenewp = new AstTime(nodep->fileline());
|
||||
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
|
||||
timesp->unlinkFrBackWithNext();
|
||||
timenewp->addNext(timesp);
|
||||
}
|
||||
nodep->fmtp()->exprsp(timenewp);
|
||||
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
|
||||
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* newIfAssertOn(AstNode* nodep) {
|
||||
// Add a internal if to check assertions are on.
|
||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||
return new AstIf (nodep->fileline(),
|
||||
// If assertions are off, have constant propagation rip them out later
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
(v3Global.opt.assertOn()
|
||||
? (AstNode*)(new AstCMath(nodep->fileline(), "Verilated::assertOn()", 1))
|
||||
: (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 0)))),
|
||||
nodep, NULL);
|
||||
}
|
||||
|
||||
AstNode* newIfCoverageOn(AstNode* nodep) {
|
||||
// Add a internal if to check coverage is on
|
||||
// Don't make this a AND term, as it's unlikely to need to test this.
|
||||
return new AstIf (nodep->fileline(),
|
||||
// If assertions are off, have constant propagation rip them out later
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
(v3Global.opt.coverage()
|
||||
? (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 1)))
|
||||
: (AstNode*)(new AstConst(nodep->fileline(), V3Number(nodep->fileline(), 1, 0)))),
|
||||
nodep, NULL);
|
||||
AstNode* newp
|
||||
= new AstIf (nodep->fileline(),
|
||||
// If assertions are off, have constant propagation rip them out later
|
||||
// This allows syntax errors and such to be detected normally.
|
||||
(v3Global.opt.assertOn()
|
||||
? (AstNode*)(new AstCMath(nodep->fileline(), "Verilated::assertOn()", 1))
|
||||
: (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicFalse()))),
|
||||
nodep, NULL);
|
||||
newp->user1(true); // Don't assert/cover this if
|
||||
return newp;
|
||||
}
|
||||
|
||||
AstNode* newFireAssert(AstNode* nodep, const string& message) {
|
||||
AstDisplay* dispp = new AstDisplay (nodep->fileline(), AstDisplayType::ERROR, message, NULL, NULL);
|
||||
AstDisplay* dispp = new AstDisplay (nodep->fileline(), AstDisplayType::DT_ERROR, message, NULL, NULL);
|
||||
AstNode* bodysp = dispp;
|
||||
replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format
|
||||
bodysp->addNext(new AstStop (nodep->fileline()));
|
||||
@@ -124,21 +116,16 @@ private:
|
||||
if (message!="") covincp->declp()->comment(message);
|
||||
bodysp = covincp;
|
||||
}
|
||||
} else if (nodep->castPslAssert()) {
|
||||
bodysp = newFireAssert(nodep,message);
|
||||
// We assert the property is always true... so report when it fails
|
||||
// (Note this is opposite the behavior of coverage statements.)
|
||||
// Need: 'never' operator: not hold in current or any future cycle
|
||||
propp = new AstLogNot (nodep->fileline(), propp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown node type");
|
||||
}
|
||||
if (stmtsp) bodysp = bodysp->addNext(stmtsp);
|
||||
if (bodysp && stmtsp) bodysp = bodysp->addNext(stmtsp);
|
||||
AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
|
||||
bodysp = ifp;
|
||||
if (nodep->castPslAssert()) ifp->branchPred(AstBranchPred::UNLIKELY);
|
||||
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
//
|
||||
AstNode* newp = new AstAlways (nodep->fileline(),
|
||||
VAlwaysKwd::ALWAYS,
|
||||
sentreep,
|
||||
bodysp);
|
||||
// Install it
|
||||
@@ -151,7 +138,7 @@ private:
|
||||
nodep->replaceWith(newp);
|
||||
}
|
||||
// Bye
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
|
||||
void newVAssertion(AstVAssert* nodep, AstNode* propp) {
|
||||
@@ -168,56 +155,119 @@ private:
|
||||
|
||||
AstIf* ifp = new AstIf (nodep->fileline(), propp, passsp, failsp);
|
||||
AstNode* newp = ifp;
|
||||
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::UNLIKELY);
|
||||
if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
//
|
||||
// Install it
|
||||
nodep->replaceWith(newp);
|
||||
// Bye
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstIf* nodep) {
|
||||
if (nodep->user1SetOnce()) return;
|
||||
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
AstNodeIf* ifp = nodep;
|
||||
AstNode* propp = NULL;
|
||||
bool hasDefaultElse = false;
|
||||
do {
|
||||
// If this statement ends with 'else if', then nextIf will point to the
|
||||
// nextIf statement. Otherwise it will be null.
|
||||
AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
|
||||
ifp->condp()->iterateAndNext(*this);
|
||||
|
||||
// Recurse into the true case.
|
||||
ifp->ifsp()->iterateAndNext(*this);
|
||||
|
||||
// If the last else is not an else if, recurse into that too.
|
||||
if (ifp->elsesp() && !nextifp) {
|
||||
ifp->elsesp()->iterateAndNext(*this);
|
||||
}
|
||||
|
||||
// Build a bitmask of the true predicates
|
||||
AstNode* predp = ifp->condp()->cloneTree(false);
|
||||
if (propp) {
|
||||
propp = new AstConcat(nodep->fileline(), predp, propp);
|
||||
} else {
|
||||
propp = predp;
|
||||
}
|
||||
|
||||
// Record if this ends with an 'else' that does not have an if
|
||||
if (ifp->elsesp() && !nextifp) {
|
||||
hasDefaultElse = true;
|
||||
}
|
||||
|
||||
ifp = nextifp;
|
||||
} while (ifp);
|
||||
|
||||
AstNode *newifp = nodep->cloneTree(false);
|
||||
bool allow_none = nodep->unique0Pragma();
|
||||
|
||||
// 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);
|
||||
checkifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
nodep->replaceWith(checkifp);
|
||||
pushDeletep(nodep);
|
||||
} else {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS //========== Case assertions
|
||||
virtual void visit(AstCase* nodep, AstNUser*) {
|
||||
virtual void visit(AstCase* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(true);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
bool has_default=false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
if (itemp->isDefault()) has_default=true;
|
||||
}
|
||||
if (nodep->fullPragma()) {
|
||||
if (nodep->fullPragma() || nodep->priorityPragma()) {
|
||||
// Simply need to add a default if there isn't one already
|
||||
m_statAsFull++;
|
||||
++m_statAsFull;
|
||||
if (!has_default) {
|
||||
nodep->addItemsp(new AstCaseItem(nodep->fileline(), NULL/*DEFAULT*/,
|
||||
newFireAssert(nodep, "synthesis full_case, but non-match found")));
|
||||
}
|
||||
}
|
||||
if (nodep->parallelPragma()) {
|
||||
if (nodep->parallelPragma() || nodep->uniquePragma() || nodep->unique0Pragma()) {
|
||||
// Need to check that one, and only one of the case items match at any moment
|
||||
// If there's a default, we allow none to match, else exactly one must match
|
||||
m_statAsFull++;
|
||||
++m_statAsFull;
|
||||
if (!has_default && !nodep->itemsp()) {
|
||||
// Not parallel, but harmlessly so.
|
||||
} else {
|
||||
AstNode* propp = NULL;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
|
||||
AstNode* onep = new AstEq(icondp->fileline(),
|
||||
nodep->exprp()->cloneTree(false),
|
||||
icondp->cloneTree(false));
|
||||
AstNode* onep;
|
||||
if (nodep->casex() || nodep->casez() || nodep->caseInside()) {
|
||||
onep = AstEqWild::newTyped(itemp->fileline(),
|
||||
nodep->exprp()->cloneTree(false),
|
||||
icondp->cloneTree(false));
|
||||
} else {
|
||||
onep = AstEq::newTyped(icondp->fileline(),
|
||||
nodep->exprp()->cloneTree(false),
|
||||
icondp->cloneTree(false));
|
||||
}
|
||||
if (propp) propp = new AstConcat(icondp->fileline(), onep, propp);
|
||||
else propp = onep;
|
||||
}
|
||||
}
|
||||
AstNode* ohot = (has_default
|
||||
? (new AstOneHot0(nodep->fileline(), propp))->castNode()
|
||||
: (new AstOneHot (nodep->fileline(), propp))->castNode());
|
||||
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);
|
||||
ifp->branchPred(AstBranchPred::UNLIKELY);
|
||||
ifp->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
nodep->addNotParallelp(ifp);
|
||||
}
|
||||
}
|
||||
@@ -225,46 +275,40 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS //========== Statements
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
virtual void visit(AstDisplay* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Replace the special types with standard text
|
||||
if (nodep->displayType()==AstDisplayType::INFO) {
|
||||
if (nodep->displayType()==AstDisplayType::DT_INFO) {
|
||||
replaceDisplay(nodep, "-Info");
|
||||
} else if (nodep->displayType()==AstDisplayType::WARNING) {
|
||||
} else if (nodep->displayType()==AstDisplayType::DT_WARNING) {
|
||||
replaceDisplay(nodep, "%%Warning");
|
||||
} else if (nodep->displayType()==AstDisplayType::ERROR
|
||||
|| nodep->displayType()==AstDisplayType::FATAL) {
|
||||
} else if (nodep->displayType()==AstDisplayType::DT_ERROR
|
||||
|| nodep->displayType()==AstDisplayType::DT_FATAL) {
|
||||
replaceDisplay(nodep, "%%Error");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstPslCover* nodep, AstNUser*) {
|
||||
virtual void visit(AstPslCover* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
|
||||
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
|
||||
nodep->stmtsp(), nodep->name()); nodep=NULL;
|
||||
m_statAsCover++;
|
||||
nodep->stmtsp(), nodep->name()); VL_DANGLING(nodep);
|
||||
++m_statAsCover;
|
||||
}
|
||||
virtual void visit(AstPslAssert* nodep, AstNUser*) {
|
||||
virtual void visit(AstVAssert* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
|
||||
NULL, nodep->name()); nodep=NULL;
|
||||
m_statAsPsl++;
|
||||
}
|
||||
virtual void visit(AstVAssert* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
newVAssertion(nodep, nodep->propp()); nodep=NULL;
|
||||
m_statAsSV++;
|
||||
newVAssertion(nodep, nodep->propp()); VL_DANGLING(nodep);
|
||||
++m_statAsSV;
|
||||
}
|
||||
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
//
|
||||
nodep->iterateChildren(*this);
|
||||
// Reset defaults
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep, AstNUser*) {
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
// This code is needed rather than a visitor in V3Begin,
|
||||
// because V3Assert is called before V3Begin
|
||||
AstBegin* lastp = m_beginp;
|
||||
@@ -275,20 +319,12 @@ private:
|
||||
m_beginp = lastp;
|
||||
}
|
||||
|
||||
// VISITORS //========== Temporal Layer
|
||||
|
||||
// VISITORS //========== Boolean Layer
|
||||
virtual void visit(AstPslBool* nodep, AstNUser*) {
|
||||
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
AssertVisitor(AstNetlist* nodep) {
|
||||
explicit AssertVisitor(AstNetlist* nodep) {
|
||||
m_beginp = NULL;
|
||||
m_modp = NULL;
|
||||
// Process
|
||||
@@ -308,4 +344,5 @@ public:
|
||||
void V3Assert::assertAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
AssertVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("assert", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Assertion expansion
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2017 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.
|
||||
|
||||
+12
-27
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Collect and print statistics
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2017 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.
|
||||
@@ -74,15 +73,7 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS //========== Statements
|
||||
virtual void visit(AstPslDefClock* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Store the new default clock, reset on new module
|
||||
m_seniDefaultp = nodep->sensesp();
|
||||
// Trash it
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstClocking* nodep, AstNUser*) {
|
||||
virtual void visit(AstClocking* nodep) {
|
||||
UINFO(8," CLOCKING"<<nodep<<endl);
|
||||
// Store the new default clock, reset on new module
|
||||
m_seniDefaultp = nodep->sensesp();
|
||||
@@ -92,27 +83,20 @@ private:
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
|
||||
virtual void visit(AstPslCover* nodep, AstNUser*) {
|
||||
virtual void visit(AstPslCover* nodep) {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
clearAssertInfo();
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
clearAssertInfo();
|
||||
}
|
||||
virtual void visit(AstPslAssert* nodep, AstNUser*) {
|
||||
if (nodep->sentreep()) return; // Already processed
|
||||
clearAssertInfo();
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->sentreep(newSenTree(nodep));
|
||||
clearAssertInfo();
|
||||
}
|
||||
virtual void visit(AstPslClocked* nodep, AstNUser*) {
|
||||
virtual void visit(AstPslClocked* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (m_senip) {
|
||||
nodep->v3error("Unsupported: Only one PSL clock allowed per assertion\n");
|
||||
nodep->v3error("Unsupported: Only one PSL clock allowed per assertion");
|
||||
}
|
||||
// Block is the new expression to evaluate
|
||||
AstNode* blockp = nodep->propp()->unlinkFrBack();
|
||||
@@ -125,20 +109,20 @@ private:
|
||||
// Unlink and just keep a pointer to it, convert to sentree as needed
|
||||
m_senip = nodep->sensesp();
|
||||
nodep->replaceWith(blockp);
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Reset defaults
|
||||
m_seniDefaultp = NULL;
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
AssertPreVisitor(AstNetlist* nodep) {
|
||||
explicit AssertPreVisitor(AstNetlist* nodep) {
|
||||
m_seniDefaultp = NULL;
|
||||
clearAssertInfo();
|
||||
// Process
|
||||
@@ -153,4 +137,5 @@ public:
|
||||
void V3AssertPre::assertPreAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
AssertPreVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("assertpre", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Assertion pre-expansion
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2005-2017 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.
|
||||
|
||||
+375
-157
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Ast node structures
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -29,12 +28,13 @@
|
||||
#include "V3File.h"
|
||||
#include "V3Global.h"
|
||||
#include "V3Broken.h"
|
||||
#include "V3String.h"
|
||||
|
||||
//======================================================================
|
||||
// Statics
|
||||
|
||||
vluint64_t AstNode::s_editCntGbl=0;
|
||||
vluint64_t AstNode::s_editCntLast=0;
|
||||
vluint64_t AstNode::s_editCntGbl=0; // Hot cache line
|
||||
|
||||
// To allow for fast clearing of all user pointers, we keep a "timestamp"
|
||||
// along with each userp, and thus by bumping this count we can make it look
|
||||
@@ -44,11 +44,16 @@ uint32_t AstUser1InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
uint32_t AstUser2InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
uint32_t AstUser3InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
uint32_t AstUser4InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
uint32_t AstUser5InUse::s_userCntGbl=0; // Hot cache line, leave adjacent
|
||||
|
||||
bool AstUser1InUse::s_userBusy=false;
|
||||
bool AstUser2InUse::s_userBusy=false;
|
||||
bool AstUser3InUse::s_userBusy=false;
|
||||
bool AstUser4InUse::s_userBusy=false;
|
||||
bool AstUser5InUse::s_userBusy=false;
|
||||
|
||||
int AstNodeDType::s_uniqueNum = 0;
|
||||
|
||||
|
||||
//######################################################################
|
||||
// V3AstType
|
||||
@@ -69,34 +74,36 @@ void AstNode::init() {
|
||||
m_op3p = NULL;
|
||||
m_op4p = NULL;
|
||||
m_iterpp = NULL;
|
||||
m_dtypep = NULL;
|
||||
m_clonep = NULL;
|
||||
m_cloneCnt = 0;
|
||||
// Attributes
|
||||
m_signed = false;
|
||||
m_width = 0;
|
||||
m_widthMin = 0;
|
||||
m_user1p = NULL;
|
||||
m_didWidth = false;
|
||||
m_doingWidth = false;
|
||||
m_user1u = VNUser(0);
|
||||
m_user1Cnt = 0;
|
||||
m_user2p = NULL;
|
||||
m_user2u = VNUser(0);
|
||||
m_user2Cnt = 0;
|
||||
m_user3p = NULL;
|
||||
m_user3u = VNUser(0);
|
||||
m_user3Cnt = 0;
|
||||
m_user4p = NULL;
|
||||
m_user4u = VNUser(0);
|
||||
m_user4Cnt = 0;
|
||||
m_user5u = VNUser(0);
|
||||
m_user5Cnt = 0;
|
||||
}
|
||||
|
||||
string AstNode::encodeName(const string& namein) {
|
||||
// Encode signal name raw from parser, then not called again on same signal
|
||||
const char* start = namein.c_str();
|
||||
string out;
|
||||
for (const char* pos = start; *pos; pos++) {
|
||||
if ((pos==start) ? isalpha(pos[0]) // digits can't lead identifiers
|
||||
for (string::const_iterator pos = namein.begin(); pos!=namein.end(); ++pos) {
|
||||
if ((pos==namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers
|
||||
: isalnum(pos[0])) {
|
||||
out += pos[0];
|
||||
} else if (pos[0]=='_') {
|
||||
if (pos[1]=='_') {
|
||||
out += "_"; out += "__05F"; // hex(_) = 0x5F
|
||||
pos++;
|
||||
++pos;
|
||||
if (pos==namein.end()) break;
|
||||
} else {
|
||||
out += pos[0];
|
||||
}
|
||||
@@ -109,6 +116,10 @@ string AstNode::encodeName(const string& namein) {
|
||||
out += hex;
|
||||
}
|
||||
}
|
||||
// Shorten names
|
||||
// TODO long term use VName in place of "string name"
|
||||
VName vname(out);
|
||||
out = vname.hashedName();
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -139,40 +150,69 @@ string AstNode::dedotName(const string& namein) {
|
||||
return pretty;
|
||||
}
|
||||
|
||||
string AstNode::vcdName(const string& namein) {
|
||||
// VCD tracing expects space to separate hierarchy
|
||||
// Dots are reserved for dots the user put in the name
|
||||
string pretty = namein;
|
||||
string::size_type pos;
|
||||
while ((pos=pretty.find("__DOT__")) != string::npos) {
|
||||
pretty.replace(pos, 7, " ");
|
||||
}
|
||||
while ((pos=pretty.find(".")) != string::npos) {
|
||||
pretty.replace(pos, 1, " ");
|
||||
}
|
||||
// Now convert escaped special characters, etc
|
||||
return prettyName(pretty);
|
||||
}
|
||||
|
||||
string AstNode::prettyName(const string& namein) {
|
||||
// This function is somewhat hot, so we short-circuit some compares
|
||||
string pretty;
|
||||
pretty = "";
|
||||
pretty.reserve(namein.length());
|
||||
for (const char* pos = namein.c_str(); *pos; ) {
|
||||
if (0==strncmp(pos,"__BRA__",7)) {
|
||||
pretty += "[";
|
||||
pos += 7;
|
||||
}
|
||||
else if (0==strncmp(pos,"__KET__",7)) {
|
||||
pretty += "]";
|
||||
pos += 7;
|
||||
}
|
||||
else if (0==strncmp(pos,"__DOT__",7)) {
|
||||
if (pos[0]=='-' && pos[1]=='>') { // ->
|
||||
pretty += ".";
|
||||
pos += 7;
|
||||
pos += 2;
|
||||
continue;
|
||||
}
|
||||
else if (0==strncmp(pos,"__PVT__",7)) {
|
||||
pretty += "";
|
||||
pos += 7;
|
||||
}
|
||||
else if (pos[0]=='_' && pos[1]=='_' && pos[2]=='0'
|
||||
&& isxdigit(pos[3]) && isxdigit(pos[4])) {
|
||||
char value = 0;
|
||||
value += 16*(isdigit(pos[3]) ? (pos[3]-'0') : (tolower(pos[3])-'a'+10));
|
||||
value += (isdigit(pos[4]) ? (pos[4]-'0') : (tolower(pos[4])-'a'+10));
|
||||
pretty += value;
|
||||
pos += 5;
|
||||
}
|
||||
else {
|
||||
pretty += pos[0];
|
||||
pos++;
|
||||
if (pos[0]=='_' && pos[1]=='_') { // Short-circuit
|
||||
if (0==strncmp(pos,"__BRA__",7)) {
|
||||
pretty += "[";
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (0==strncmp(pos,"__KET__",7)) {
|
||||
pretty += "]";
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (0==strncmp(pos,"__DOT__",7)) {
|
||||
pretty += ".";
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (0==strncmp(pos,"__PVT__",7)) {
|
||||
pretty += "";
|
||||
pos += 7;
|
||||
continue;
|
||||
}
|
||||
if (pos[0]=='_' && pos[1]=='_' && pos[2]=='0'
|
||||
&& isxdigit(pos[3]) && isxdigit(pos[4])) {
|
||||
char value = 0;
|
||||
value += 16*(isdigit(pos[3]) ? (pos[3]-'0') : (tolower(pos[3])-'a'+10));
|
||||
value += (isdigit(pos[4]) ? (pos[4]-'0') : (tolower(pos[4])-'a'+10));
|
||||
pretty += value;
|
||||
pos += 5;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// Default
|
||||
pretty += pos[0];
|
||||
++pos;
|
||||
}
|
||||
if (pretty.substr(0,4) == "TOP.") pretty.replace(0,4,"");
|
||||
if (pretty[0]=='T' && pretty.substr(0,4) == "TOP.") pretty.replace(0,4,"");
|
||||
if (pretty[0]=='T' && pretty.substr(0,5) == "TOP->") pretty.replace(0,5,"");
|
||||
return pretty;
|
||||
}
|
||||
|
||||
@@ -181,15 +221,6 @@ string AstNode::prettyTypeName() const {
|
||||
return string(typeName())+" '"+prettyName()+"'";
|
||||
}
|
||||
|
||||
int AstNode::widthPow2() const {
|
||||
// I.e. width 30 returns 32, width 32 returns 32.
|
||||
uint32_t width = this->width();
|
||||
for (int p2=30; p2>=0; p2--) {
|
||||
if (width > (1UL<<p2)) return (1UL<<(p2+1));
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// Insertion
|
||||
|
||||
@@ -198,9 +229,12 @@ inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next)
|
||||
// Called on all major tree changers.
|
||||
// Only for use for those really nasty bugs relating to internals
|
||||
// Note this may be null.
|
||||
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<": "<<(void*)this<<endl;
|
||||
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<": "<<(void*)this<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
|
||||
//if (debug()) {
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// // Commenting out the section below may crash, as the tree state
|
||||
// // between edits is not always consistent for printing
|
||||
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
|
||||
// v3Global.rootp()->dumpTree(cout,"-treeChange: ");
|
||||
// if (next||1) this->dumpTreeAndNext(cout, prefix);
|
||||
// else this->dumpTree(cout, prefix);
|
||||
@@ -210,20 +244,20 @@ inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next)
|
||||
#endif
|
||||
}
|
||||
|
||||
AstNode* AstNode::addNext(AstNode* newp) {
|
||||
AstNode* AstNode::addNext(AstNode* nodep, AstNode* newp) {
|
||||
// Add to m_nextp, returns this
|
||||
UASSERT(newp,"Null item passed to addNext\n");
|
||||
this->debugTreeChange("-addNextThs: ", __LINE__, false);
|
||||
UDEBUGONLY(if (!newp) nodep->v3fatalSrc("Null item passed to addNext"););
|
||||
nodep->debugTreeChange("-addNextThs: ", __LINE__, false);
|
||||
newp->debugTreeChange("-addNextNew: ", __LINE__, true);
|
||||
if (this == NULL) {
|
||||
if (!nodep) { // verilog.y and lots of other places assume this
|
||||
return (newp);
|
||||
} else {
|
||||
// Find end of old list
|
||||
AstNode* oldtailp = this;
|
||||
AstNode* oldtailp = nodep;
|
||||
if (oldtailp->m_nextp) {
|
||||
if (oldtailp->m_headtailp) {
|
||||
oldtailp = oldtailp->m_headtailp; // This=beginning of list, jump to end
|
||||
UASSERT(!oldtailp->m_nextp, "Node had next, but headtail says it shouldn't");
|
||||
UDEBUGONLY(if (oldtailp->m_nextp) nodep->v3fatalSrc("Node had next, but headtail says it shouldn't"););
|
||||
} else {
|
||||
// Though inefficent, we are occasionally passed a addNext in the middle of a list.
|
||||
while (oldtailp->m_nextp != NULL) oldtailp = oldtailp->m_nextp;
|
||||
@@ -242,21 +276,21 @@ AstNode* AstNode::addNext(AstNode* newp) {
|
||||
newp->editCountInc();
|
||||
if (oldtailp->m_iterpp) *(oldtailp->m_iterpp) = newp; // Iterate on new item
|
||||
}
|
||||
this->debugTreeChange("-addNextOut:", __LINE__, true);
|
||||
return this;
|
||||
nodep->debugTreeChange("-addNextOut:", __LINE__, true);
|
||||
return nodep;
|
||||
}
|
||||
|
||||
AstNode* AstNode::addNextNull(AstNode* newp) {
|
||||
if (!newp) return this;
|
||||
return addNext(newp);
|
||||
AstNode* AstNode::addNextNull(AstNode* nodep, AstNode* newp) {
|
||||
if (!newp) return nodep;
|
||||
return addNext(nodep, newp);
|
||||
}
|
||||
|
||||
void AstNode::addNextHere(AstNode* newp) {
|
||||
// Add to m_nextp on exact node passed, not at the end.
|
||||
// This could be at head, tail, or both (single)
|
||||
// New could be head of single node, or list
|
||||
UDEBUGONLY(UASSERT(dynamic_cast<AstNode*>(this),"this should not be NULL"););
|
||||
UASSERT(newp,"Null item passed to addNext");
|
||||
UASSERT(this,"Null base node");
|
||||
UASSERT(newp->backp()==NULL,"New node (back) already assigned?");
|
||||
this->debugTreeChange("-addHereThs: ", __LINE__, false);
|
||||
newp->debugTreeChange("-addHereNew: ", __LINE__, true);
|
||||
@@ -383,7 +417,7 @@ void AstNode::replaceWith(AstNode* newp) {
|
||||
repHandle.relink(newp);
|
||||
}
|
||||
|
||||
void AstNRelinker::dump(ostream& str) {
|
||||
void AstNRelinker::dump(ostream& str) const {
|
||||
str<<" BK="<<(uint32_t*)m_backp;
|
||||
str<<" ITER="<<(uint32_t*)m_iterpp;
|
||||
str<<" CHG="<<(m_chg==RELINK_NEXT?"[NEXT] ":"");
|
||||
@@ -523,7 +557,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
|
||||
if (linkerp->m_iterpp) {
|
||||
// If we're iterating over a next() link, we need to follow links off the
|
||||
// NEW node. Thus we pass iteration information via a pointer in the node.
|
||||
// This adds a unfortunate 4 bytes to every AstNode, but is faster than passing
|
||||
// This adds a unfortunate hot 8 bytes to every AstNode, but is faster than passing
|
||||
// across every function.
|
||||
// If anyone has a cleaner way, I'd be grateful.
|
||||
*(linkerp->m_iterpp) = newp;
|
||||
@@ -559,16 +593,33 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
|
||||
pointpr = newp;
|
||||
}
|
||||
|
||||
void AstNode::addHereThisAsNext (AstNode* newp) {
|
||||
// {old}->this->{next} becomes {old}->new->this->{next}
|
||||
AstNRelinker handle;
|
||||
this->unlinkFrBackWithNext(&handle);
|
||||
newp->addNext(this);
|
||||
handle.relink(newp);
|
||||
}
|
||||
|
||||
void AstNode::swapWith (AstNode* bp) {
|
||||
AstNRelinker aHandle;
|
||||
AstNRelinker bHandle;
|
||||
this->unlinkFrBack(&aHandle);
|
||||
bp->unlinkFrBack(&bHandle);
|
||||
aHandle.relink(bp);
|
||||
bHandle.relink(this);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Clone
|
||||
|
||||
AstNode* AstNode::cloneTreeIter() {
|
||||
if (!this) return NULL;
|
||||
// private: Clone single node and children
|
||||
AstNode* newp = this->clone();
|
||||
newp->op1p(this->m_op1p->cloneTreeIterList());
|
||||
newp->op2p(this->m_op2p->cloneTreeIterList());
|
||||
newp->op3p(this->m_op3p->cloneTreeIterList());
|
||||
newp->op4p(this->m_op4p->cloneTreeIterList());
|
||||
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList());
|
||||
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList());
|
||||
if (this->m_op3p) newp->op3p(this->m_op3p->cloneTreeIterList());
|
||||
if (this->m_op4p) newp->op4p(this->m_op4p->cloneTreeIterList());
|
||||
newp->m_iterpp = NULL;
|
||||
newp->clonep(this); // Save pointers to/from both to simplify relinking.
|
||||
this->clonep(newp); // Save pointers to/from both to simplify relinking.
|
||||
@@ -576,10 +627,10 @@ AstNode* AstNode::cloneTreeIter() {
|
||||
}
|
||||
|
||||
AstNode* AstNode::cloneTreeIterList() {
|
||||
// Clone list of nodes, set m_headtailp
|
||||
if (!this) return NULL;
|
||||
// private: Clone list of nodes, set m_headtailp
|
||||
AstNode* newheadp = NULL;
|
||||
AstNode* newtailp = NULL;
|
||||
// Audited to make sure this is never NULL
|
||||
for (AstNode* oldp = this; oldp; oldp=oldp->m_nextp) {
|
||||
AstNode* newp = oldp->cloneTreeIter();
|
||||
newp->m_headtailp = NULL;
|
||||
@@ -594,7 +645,7 @@ AstNode* AstNode::cloneTreeIterList() {
|
||||
}
|
||||
|
||||
AstNode* AstNode::cloneTree(bool cloneNextLink) {
|
||||
if (!this) return NULL;
|
||||
if (!this) return NULL; // verilog.y relies on this
|
||||
this->debugTreeChange("-cloneThs: ", __LINE__, cloneNextLink);
|
||||
cloneClearTree();
|
||||
AstNode* newp;
|
||||
@@ -615,7 +666,7 @@ AstNode* AstNode::cloneTree(bool cloneNextLink) {
|
||||
// Delete
|
||||
|
||||
void AstNode::deleteNode() {
|
||||
if (!this) return;
|
||||
// private: Delete single node. Publicly call deleteTree() instead.
|
||||
UASSERT(m_backp==NULL,"Delete called on node with backlink still set\n");
|
||||
editCountInc();
|
||||
// Change links of old node so we coredump if used
|
||||
@@ -635,23 +686,27 @@ AstNode::~AstNode() {
|
||||
}
|
||||
|
||||
void AstNode::deleteTreeIter() {
|
||||
if (!this) return;
|
||||
// MUST be depth first!
|
||||
this->m_op1p->deleteTreeIter();
|
||||
this->m_op2p->deleteTreeIter();
|
||||
this->m_op3p->deleteTreeIter();
|
||||
this->m_op4p->deleteTreeIter();
|
||||
this->m_nextp->deleteTreeIter();
|
||||
this->m_backp = NULL;
|
||||
deleteNode();
|
||||
// private: Delete list of nodes. Publicly call deleteTree() instead.
|
||||
// Audited to make sure this is never NULL
|
||||
for (AstNode* nodep=this, *nnextp; nodep; nodep=nnextp) {
|
||||
nnextp = nodep->m_nextp;
|
||||
// MUST be depth first!
|
||||
if (nodep->m_op1p) nodep->m_op1p->deleteTreeIter();
|
||||
if (nodep->m_op2p) nodep->m_op2p->deleteTreeIter();
|
||||
if (nodep->m_op3p) nodep->m_op3p->deleteTreeIter();
|
||||
if (nodep->m_op4p) nodep->m_op4p->deleteTreeIter();
|
||||
nodep->m_nextp = NULL;
|
||||
nodep->m_backp = NULL;
|
||||
nodep->deleteNode();
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::deleteTree() {
|
||||
// deleteTree always deletes the next link, because you must have called
|
||||
// unlinkFromBack or unlinkFromBackWithNext as appropriate before calling this.
|
||||
if (!this) return;
|
||||
UASSERT(m_backp==NULL,"Delete called on node with backlink still set\n");
|
||||
this->debugTreeChange("-delTree: ", __LINE__, true);
|
||||
this->editCountInc();
|
||||
// MUST be depth first!
|
||||
deleteTreeIter();
|
||||
}
|
||||
@@ -661,6 +716,7 @@ void AstNode::deleteTree() {
|
||||
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
void* AstNode::operator new(size_t size) {
|
||||
// Optimization note: Aligning to cache line is a loss, due to lost packing
|
||||
AstNode* objp = static_cast<AstNode*>(::operator new(size));
|
||||
V3Broken::addNewed(objp);
|
||||
return objp;
|
||||
@@ -677,120 +733,188 @@ void AstNode::operator delete(void* objp, size_t size) {
|
||||
//======================================================================
|
||||
// Iterators
|
||||
|
||||
void AstNode::iterateChildren(AstNVisitor& v, AstNUser* vup) {
|
||||
void AstNode::iterateChildren(AstNVisitor& v) {
|
||||
// This is a very hot function
|
||||
if (!this) return;
|
||||
// Optimization note: Grabbing m_op#p->m_nextp is a net loss
|
||||
ASTNODE_PREFETCH(m_op1p);
|
||||
ASTNODE_PREFETCH(m_op2p);
|
||||
ASTNODE_PREFETCH(m_op3p);
|
||||
ASTNODE_PREFETCH(m_op4p);
|
||||
// if () not needed since iterateAndNext accepts null this, but faster with it.
|
||||
if (m_op1p) m_op1p->iterateAndNext(v, vup);
|
||||
if (m_op2p) m_op2p->iterateAndNext(v, vup);
|
||||
if (m_op3p) m_op3p->iterateAndNext(v, vup);
|
||||
if (m_op4p) m_op4p->iterateAndNext(v, vup);
|
||||
if (m_op1p) m_op1p->iterateAndNext(v);
|
||||
if (m_op2p) m_op2p->iterateAndNext(v);
|
||||
if (m_op3p) m_op3p->iterateAndNext(v);
|
||||
if (m_op4p) m_op4p->iterateAndNext(v);
|
||||
}
|
||||
|
||||
void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) {
|
||||
void AstNode::iterateChildrenConst(AstNVisitor& v) {
|
||||
// This is a very hot function
|
||||
ASTNODE_PREFETCH(m_op1p);
|
||||
ASTNODE_PREFETCH(m_op2p);
|
||||
ASTNODE_PREFETCH(m_op3p);
|
||||
ASTNODE_PREFETCH(m_op4p);
|
||||
if (m_op1p) m_op1p->iterateAndNextConst(v);
|
||||
if (m_op2p) m_op2p->iterateAndNextConst(v);
|
||||
if (m_op3p) m_op3p->iterateAndNextConst(v);
|
||||
if (m_op4p) m_op4p->iterateAndNextConst(v);
|
||||
}
|
||||
|
||||
void AstNode::iterateAndNext(AstNVisitor& v) {
|
||||
// This is a very hot function
|
||||
// IMPORTANT: If you replace a node that's the target of this iterator,
|
||||
// then the NEW node will be iterated on next, it isn't skipped!
|
||||
// if (!this) return; // Part of for()
|
||||
for (AstNode* nodep=this; nodep;) {
|
||||
AstNode* niterp = nodep;
|
||||
ASTNODE_PREFETCH(nodep->m_nextp);
|
||||
// Future versions of this function may require the node to have a back to be iterated;
|
||||
// there's no lower level reason yet though the back must exist.
|
||||
AstNode* nodep=this;
|
||||
#ifdef VL_DEBUG // Otherwise too hot of a function for debug
|
||||
if (VL_UNLIKELY(nodep && !nodep->m_backp)) nodep->v3fatalSrc("iterateAndNext node has no back");
|
||||
#endif
|
||||
if (nodep) ASTNODE_PREFETCH(nodep->m_nextp);
|
||||
while (nodep) { // effectively: if (!this) return; // Callers rely on this
|
||||
if (nodep->m_nextp) ASTNODE_PREFETCH(nodep->m_nextp->m_nextp);
|
||||
AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited
|
||||
// Desirable check, but many places where multiple iterations are OK
|
||||
//if (VL_UNLIKELY(niterp->m_iterpp)) niterp->v3fatalSrc("IterateAndNext under iterateAndNext may miss edits");
|
||||
// Optimization note: Doing PREFETCH_RW on m_iterpp is a net even
|
||||
// cppcheck-suppress nullPointer
|
||||
niterp->m_iterpp = &niterp;
|
||||
niterp->accept(v, vup);
|
||||
niterp->accept(v);
|
||||
// accept may do a replaceNode and change niterp on us...
|
||||
if (!niterp) return;
|
||||
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<(void*)nodep<<" now into "<<(void*)niterp<<endl); // niterp maybe NULL, so need cast
|
||||
if (!niterp) return; // Perhaps node deleted inside accept
|
||||
niterp->m_iterpp = NULL;
|
||||
if (niterp!=nodep) { // Edited it
|
||||
if (VL_UNLIKELY(niterp!=nodep)) { // Edited node inside accept
|
||||
nodep = niterp;
|
||||
} else { // Same node, just loop
|
||||
} else { // Unchanged node, just continue loop
|
||||
nodep = niterp->m_nextp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::iterateListBackwards(AstNVisitor& v, AstNUser* vup) {
|
||||
if (!this) return;
|
||||
void AstNode::iterateListBackwards(AstNVisitor& v) {
|
||||
UDEBUGONLY(UASSERT(dynamic_cast<AstNode*>(this),"this should not be NULL"););
|
||||
AstNode* nodep=this;
|
||||
while (nodep->m_nextp) nodep=nodep->m_nextp;
|
||||
while (nodep) {
|
||||
// Edits not supported: nodep->m_iterpp = &nodep;
|
||||
nodep->accept(v, vup);
|
||||
nodep->accept(v);
|
||||
if (nodep->backp()->m_nextp == nodep) nodep=nodep->backp();
|
||||
else nodep = NULL; // else: backp points up the tree.
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::iterateChildrenBackwards(AstNVisitor& v, AstNUser* vup) {
|
||||
if (!this) return;
|
||||
this->op1p()->iterateListBackwards(v,vup);
|
||||
this->op2p()->iterateListBackwards(v,vup);
|
||||
this->op3p()->iterateListBackwards(v,vup);
|
||||
this->op4p()->iterateListBackwards(v,vup);
|
||||
void AstNode::iterateChildrenBackwards(AstNVisitor& v) {
|
||||
if (m_op1p) m_op1p->iterateListBackwards(v);
|
||||
if (m_op2p) m_op2p->iterateListBackwards(v);
|
||||
if (m_op3p) m_op3p->iterateListBackwards(v);
|
||||
if (m_op4p) m_op4p->iterateListBackwards(v);
|
||||
}
|
||||
|
||||
void AstNode::iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup) {
|
||||
void AstNode::iterateAndNextConst(AstNVisitor& v) {
|
||||
// Keep following the current list even if edits change it
|
||||
if (!this) return;
|
||||
for (AstNode* nodep=this; nodep; ) {
|
||||
if (!this) return; // A few cases could be cleaned up, but want symmetry with iterateAndNext
|
||||
for (AstNode* nodep=this; nodep; ) { // effectively: if (!this) return; // Callers rely on this
|
||||
AstNode* nnextp = nodep->m_nextp;
|
||||
nodep->accept(v, vup);
|
||||
ASTNODE_PREFETCH(nnextp);
|
||||
nodep->accept(v);
|
||||
nodep = nnextp;
|
||||
}
|
||||
}
|
||||
|
||||
AstNode* AstNode::iterateSubtreeReturnEdits(AstNVisitor& v) {
|
||||
// Some visitors perform tree edits (such as V3Const), and may even
|
||||
// replace/delete the exact nodep that the visitor is called with. If
|
||||
// this happens, the parent will lose the handle to the node that was
|
||||
// processed.
|
||||
// To solve this, this function returns the pointer to the replacement node,
|
||||
// which in many cases is just the same node that was passed in.
|
||||
AstNode* nodep = this; // Note "this" may point to bogus point later in this function
|
||||
if (nodep->castNetlist()) {
|
||||
// Calling on top level; we know the netlist won't get replaced
|
||||
nodep->accept(v);
|
||||
} else if (!nodep->backp()) {
|
||||
// Calling on standalone tree; insert a shim node so we can keep track, then delete it on completion
|
||||
AstBegin* tempp = new AstBegin(nodep->fileline(),"[EditWrapper]",nodep);
|
||||
{
|
||||
tempp->stmtsp()->accept(v); VL_DANGLING(nodep); // nodep to null as may be replaced
|
||||
}
|
||||
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
|
||||
tempp->deleteTree(); VL_DANGLING(tempp);
|
||||
} else {
|
||||
// Use back to determine who's pointing at us (IE assume new node grafts into same place as old one)
|
||||
AstNode** nextnodepp = NULL;
|
||||
if (this->m_backp->m_op1p == this) nextnodepp = &(this->m_backp->m_op1p);
|
||||
else if (this->m_backp->m_op2p == this) nextnodepp = &(this->m_backp->m_op2p);
|
||||
else if (this->m_backp->m_op3p == this) nextnodepp = &(this->m_backp->m_op3p);
|
||||
else if (this->m_backp->m_op4p == this) nextnodepp = &(this->m_backp->m_op4p);
|
||||
else if (this->m_backp->m_nextp == this) nextnodepp = &(this->m_backp->m_nextp);
|
||||
if (!nextnodepp) this->v3fatalSrc("Node's back doesn't point to forward to node itself");
|
||||
{
|
||||
nodep->accept(v); VL_DANGLING(nodep); // nodep to null as may be replaced
|
||||
}
|
||||
nodep = *nextnodepp; // Grab new node from point where old was connected
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
void AstNode::cloneRelinkTree() {
|
||||
if (!this) return;
|
||||
this->cloneRelink();
|
||||
m_op1p->cloneRelinkTree();
|
||||
m_op2p->cloneRelinkTree();
|
||||
m_op3p->cloneRelinkTree();
|
||||
m_op4p->cloneRelinkTree();
|
||||
m_nextp->cloneRelinkTree(); // Tail recursion
|
||||
// private: Cleanup clone() operation on whole tree. Publicly call cloneTree() instead.
|
||||
for (AstNode* nodep=this; nodep; nodep=nodep->m_nextp) {
|
||||
if (m_dtypep && m_dtypep->clonep()) {
|
||||
m_dtypep = m_dtypep->clonep();
|
||||
}
|
||||
nodep->cloneRelink();
|
||||
if (nodep->m_op1p) nodep->m_op1p->cloneRelinkTree();
|
||||
if (nodep->m_op2p) nodep->m_op2p->cloneRelinkTree();
|
||||
if (nodep->m_op3p) nodep->m_op3p->cloneRelinkTree();
|
||||
if (nodep->m_op4p) nodep->m_op4p->cloneRelinkTree();
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Comparison
|
||||
|
||||
bool AstNode::sameTree(AstNode* node2p) {
|
||||
return sameTreeIter(node2p, true);
|
||||
bool AstNode::gateTreeIter() {
|
||||
// private: Return true if the two trees are identical
|
||||
if (!isGateOptimizable()) return false;
|
||||
if (m_op1p && !m_op1p->gateTreeIter()) return false;
|
||||
if (m_op2p && !m_op2p->gateTreeIter()) return false;
|
||||
if (m_op3p && !m_op3p->gateTreeIter()) return false;
|
||||
if (m_op4p && !m_op4p->gateTreeIter()) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext) {
|
||||
// Return true if the two trees are identical
|
||||
if (this==NULL && node2p==NULL) return true;
|
||||
if (this==NULL || node2p==NULL) return false;
|
||||
if (this->type() != node2p->type()
|
||||
|| this->width() != node2p->width()
|
||||
|| this->isSigned() != node2p->isSigned()
|
||||
|| !this->same(node2p)) {
|
||||
bool AstNode::sameTreeIter(AstNode* node1p, AstNode* node2p, bool ignNext, bool gateOnly) {
|
||||
// private: Return true if the two trees are identical
|
||||
if (!node1p && !node2p) return true;
|
||||
if (!node1p || !node2p) return false;
|
||||
if (node1p->type() != node2p->type()
|
||||
|| node1p->dtypep() != node2p->dtypep()
|
||||
|| !node1p->same(node2p)
|
||||
|| (gateOnly && !node1p->isGateOptimizable())) {
|
||||
return false;
|
||||
}
|
||||
return (this->op1p()->sameTreeIter(node2p->op1p(),false)
|
||||
&& this->op2p()->sameTreeIter(node2p->op2p(),false)
|
||||
&& this->op3p()->sameTreeIter(node2p->op3p(),false)
|
||||
&& this->op4p()->sameTreeIter(node2p->op4p(),false)
|
||||
&& (ignNext || this->nextp()->sameTreeIter(node2p->nextp(),false))
|
||||
return (sameTreeIter(node1p->m_op1p, node2p->m_op1p,false,gateOnly)
|
||||
&& sameTreeIter(node1p->m_op2p, node2p->m_op2p,false,gateOnly)
|
||||
&& sameTreeIter(node1p->m_op3p, node2p->m_op3p,false,gateOnly)
|
||||
&& sameTreeIter(node1p->m_op4p, node2p->m_op4p,false,gateOnly)
|
||||
&& (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp,false,gateOnly))
|
||||
);
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Static utilities
|
||||
|
||||
ostream& operator<<(ostream& os, V3Hash rhs) {
|
||||
ostream& operator<<(ostream& os, const V3Hash& rhs) {
|
||||
return os<<hex<<setw(2)<<setfill('0')<<rhs.depth()
|
||||
<<"_"<<setw(6)<<setfill('0')<<rhs.hshval();
|
||||
}
|
||||
|
||||
V3Hash::V3Hash(const string& name) {
|
||||
uint32_t val = 0;
|
||||
for (const char* c=name.c_str(); *c; c++) {
|
||||
val = val*31 + *c;
|
||||
for (string::const_iterator it = name.begin(); it!=name.end(); ++it) {
|
||||
val = val*31 + *it;
|
||||
}
|
||||
setBoth(1,val);
|
||||
}
|
||||
@@ -799,6 +923,7 @@ V3Hash::V3Hash(const string& name) {
|
||||
// Debugging
|
||||
|
||||
void AstNode::checkTreeIter(AstNode* backp) {
|
||||
// private: Check a tree and children
|
||||
if (backp != this->backp()) {
|
||||
this->v3fatalSrc("Back node inconsistent");
|
||||
}
|
||||
@@ -807,15 +932,15 @@ void AstNode::checkTreeIter(AstNode* backp) {
|
||||
if (op1p()||op2p()||op3p()||op4p())
|
||||
this->v3fatalSrc("Terminal operation with non-terminals");
|
||||
}
|
||||
if (op1p()) op1p()->checkTreeIterList(this);
|
||||
if (op2p()) op2p()->checkTreeIterList(this);
|
||||
if (op3p()) op3p()->checkTreeIterList(this);
|
||||
if (op4p()) op4p()->checkTreeIterList(this);
|
||||
if (m_op1p) m_op1p->checkTreeIterList(this);
|
||||
if (m_op2p) m_op2p->checkTreeIterList(this);
|
||||
if (m_op3p) m_op3p->checkTreeIterList(this);
|
||||
if (m_op4p) m_op4p->checkTreeIterList(this);
|
||||
}
|
||||
|
||||
void AstNode::checkTreeIterList(AstNode* backp) {
|
||||
// Check a (possible) list of nodes, this is always the head of the list
|
||||
if (!this) v3fatalSrc("Null nodep");
|
||||
// private: Check a (possible) list of nodes, this is always the head of the list
|
||||
// Audited to make sure this is never NULL
|
||||
AstNode* headp = this;
|
||||
AstNode* tailp = this;
|
||||
for (AstNode* nodep=headp; nodep; nodep=nodep->nextp()) {
|
||||
@@ -829,7 +954,6 @@ void AstNode::checkTreeIterList(AstNode* backp) {
|
||||
}
|
||||
|
||||
void AstNode::checkTree() {
|
||||
if (!this) return;
|
||||
if (!debug()) return;
|
||||
if (this->backp()) {
|
||||
// Linked tree- check only the passed node
|
||||
@@ -839,7 +963,35 @@ void AstNode::checkTree() {
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::dumpPtrs(ostream& os) {
|
||||
void AstNode::dumpGdb() { // For GDB only
|
||||
if (!dynamic_cast<const AstNode*>(this)) { cout<<"This=NULL"<<endl; return; }
|
||||
dumpGdbHeader();
|
||||
cout<<" "; dump(cout); cout<<endl;
|
||||
}
|
||||
void AstNode::dumpGdbHeader() const { // For GDB only
|
||||
if (!dynamic_cast<const AstNode*>(this)) { cout<<"This=NULL"<<endl; return; }
|
||||
dumpPtrs(cout);
|
||||
cout<<" Fileline = "<<fileline()<<endl;
|
||||
}
|
||||
void AstNode::dumpTreeGdb() { // For GDB only
|
||||
if (!dynamic_cast<const AstNode*>(this)) { cout<<"This=NULL"<<endl; return; }
|
||||
dumpGdbHeader();
|
||||
dumpTree(cout);
|
||||
}
|
||||
void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only
|
||||
string filename = filenamep ? filenamep : v3Global.debugFilename("debug",98);
|
||||
v3Global.rootp()->dumpTreeFile(filename);
|
||||
}
|
||||
|
||||
void AstNode::checkIter() const {
|
||||
if (m_iterpp) {
|
||||
dumpPtrs(cout);
|
||||
// Perhaps something forgot to clear m_iterpp?
|
||||
this->v3fatalSrc("Iteration link should be NULL");
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::dumpPtrs(ostream& os) const {
|
||||
os<<"This="<<typeName()<<" "<<(void*)this;
|
||||
os<<" back="<<(void*)backp();
|
||||
if (nextp()) os<<" next="<<(void*)nextp();
|
||||
@@ -853,6 +1005,7 @@ void AstNode::dumpPtrs(ostream& os) {
|
||||
if (user2p()) os<<" user2p="<<(void*)user2p();
|
||||
if (user3p()) os<<" user3p="<<(void*)user3p();
|
||||
if (user4p()) os<<" user4p="<<(void*)user4p();
|
||||
if (user5p()) os<<" user5p="<<(void*)user5p();
|
||||
if (m_iterpp) {
|
||||
os<<" iterpp="<<(void*)m_iterpp;
|
||||
os<<"*="<<(void*)*m_iterpp;
|
||||
@@ -861,7 +1014,6 @@ void AstNode::dumpPtrs(ostream& os) {
|
||||
}
|
||||
|
||||
void AstNode::dumpTree(ostream& os, const string& indent, int maxDepth) {
|
||||
if (!this) return;
|
||||
os<<indent<<" "<<this<<endl;
|
||||
if (debug()>8) { os<<indent<<" "; dumpPtrs(os); }
|
||||
if (maxDepth==1) {
|
||||
@@ -875,20 +1027,22 @@ void AstNode::dumpTree(ostream& os, const string& indent, int maxDepth) {
|
||||
}
|
||||
|
||||
void AstNode::dumpTreeAndNext(ostream& os, const string& indent, int maxDepth) {
|
||||
if (!this) return;
|
||||
// Audited to make sure this is never NULL
|
||||
for (AstNode* nodep=this; nodep; nodep=nodep->nextp()) {
|
||||
nodep->dumpTree(os, indent, maxDepth);
|
||||
}
|
||||
}
|
||||
|
||||
void AstNode::dumpTreeFile(const string& filename, bool append) {
|
||||
if (v3Global.opt.dumpTree()) {
|
||||
void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump) {
|
||||
if (doDump) {
|
||||
{ // Write log & close
|
||||
const auto_ptr<ofstream> logsp (V3File::new_ofstream(filename, append));
|
||||
UINFO(2,"Dumping "<<filename<<endl);
|
||||
const VL_UNIQUE_PTR<ofstream> logsp (V3File::new_ofstream(filename, append));
|
||||
if (logsp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
*logsp<<"Tree Dump from <e"<<dec<<editCountLast()<<">";
|
||||
*logsp<<"Verilator Tree Dump (format 0x3900) from <e"<<dec<<editCountLast()<<">";
|
||||
*logsp<<" to <e"<<dec<<editCountGbl()<<">"<<endl;
|
||||
if (editCountGbl()==editCountLast()) {
|
||||
if (editCountGbl()==editCountLast()
|
||||
&& !(v3Global.opt.dumpTree()>=9)) {
|
||||
*logsp<<endl;
|
||||
*logsp<<"No changes since last dump!\n";
|
||||
} else {
|
||||
@@ -907,21 +1061,85 @@ void AstNode::dumpTreeFile(const string& filename, bool append) {
|
||||
editCountSetLast();
|
||||
}
|
||||
|
||||
void AstNode::v3errorEndFatal(ostringstream& str) const { v3errorEnd(str); assert(0); }
|
||||
|
||||
void AstNode::v3errorEnd(ostringstream& str) const {
|
||||
if (this && m_fileline) {
|
||||
if (!dynamic_cast<const AstNode*>(this)) {
|
||||
// No known cases cause this, but better than a core dump
|
||||
if (debug()) UINFO(0, "-node: NULL. Please report this along with a --gdbbt backtrace as a Verilator bug.\n");
|
||||
V3Error::v3errorEnd(str);
|
||||
} else if (!m_fileline) {
|
||||
V3Error::v3errorEnd(str);
|
||||
} else {
|
||||
ostringstream nsstr;
|
||||
nsstr<<str.str();
|
||||
if (debug()) {
|
||||
nsstr<<endl;
|
||||
nsstr<<"-node: "<<this<<endl;
|
||||
nsstr<<"-node: "; ((AstNode*)this)->dump(nsstr); nsstr<<endl;
|
||||
}
|
||||
m_fileline->v3errorEnd(nsstr);
|
||||
} else {
|
||||
V3Error::v3errorEnd(str);
|
||||
}
|
||||
}
|
||||
|
||||
string AstNode::warnMore() const {
|
||||
return fileline()->warnMore();
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
// Data type conversion
|
||||
|
||||
void AstNode::dtypeChgSigned(bool flag) {
|
||||
if (!dtypep()) this->v3fatalSrc("No dtype when changing to (un)signed");
|
||||
dtypeChgWidthSigned(dtypep()->width(), dtypep()->widthMin(),
|
||||
flag ? AstNumeric::SIGNED : AstNumeric::UNSIGNED);
|
||||
}
|
||||
void AstNode::dtypeChgWidth(int width, int widthMin) {
|
||||
if (!dtypep()) this->v3fatalSrc("No dtype when changing width"); // Use ChgWidthSigned(...UNSIGNED) otherwise
|
||||
dtypeChgWidthSigned(width, widthMin, dtypep()->numeric());
|
||||
}
|
||||
|
||||
void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) {
|
||||
if (!dtypep()) {
|
||||
// We allow dtypep() to be null, as before/during widthing dtypes are not resolved
|
||||
dtypeSetLogicSized(width, widthMin, numeric);
|
||||
} else {
|
||||
if (width==dtypep()->width()
|
||||
&& widthMin==dtypep()->widthMin()
|
||||
&& numeric==dtypep()->numeric()) return; // Correct already
|
||||
// FUTURE: We may be pointing at a two state data type, and this may
|
||||
// convert it to logic. Since the AstVar remains correct, we
|
||||
// work OK but this assumption may break in the future.
|
||||
// Note we can't just clone and do a widthForce, as if it's a BasicDType
|
||||
// the msb() indications etc will be incorrect.
|
||||
dtypeSetLogicSized(width, widthMin, numeric);
|
||||
}
|
||||
}
|
||||
|
||||
AstNodeDType* AstNode::findBasicDType(AstBasicDTypeKwd kwd) const {
|
||||
// For 'simple' types we use the global directory. These are all unsized.
|
||||
// More advanced types land under the module/task/etc
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findBasicDType(fileline(), kwd);
|
||||
}
|
||||
AstNodeDType* AstNode::findBitDType(int width, int widthMin, AstNumeric numeric) const {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::BIT, width, widthMin, numeric);
|
||||
}
|
||||
AstNodeDType* AstNode::findLogicDType(int width, int widthMin, AstNumeric numeric) const {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, width, widthMin, numeric);
|
||||
}
|
||||
AstNodeDType* AstNode::findLogicRangeDType(VNumRange range, int widthMin, AstNumeric numeric) const {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, range, widthMin, numeric);
|
||||
}
|
||||
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
|
||||
return v3Global.rootp()->typeTablep()
|
||||
->findInsertSameDType(nodep);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// AstNVisitor
|
||||
|
||||
void AstNVisitor::doDeletes() {
|
||||
for (vector<AstNode*>::iterator it = m_deleteps.begin(); it != m_deleteps.end(); ++it) {
|
||||
|
||||
+1118
-286
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,33 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Ast node structure
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3ASTCONSTONLY_H_
|
||||
#define _V3ASTCONSTONLY_H_ 1
|
||||
|
||||
// Include only in visitors that do not not edit nodes, so should use constant iterators
|
||||
#define iterateAndNext error_use_iterateAndNextConst
|
||||
#define iterateChildren error_use_iterateChildrenConst
|
||||
|
||||
#define addNext error_no_addNext_in_ConstOnlyVisitor
|
||||
#define replaceWith error_no_replaceWith_in_ConstOnlyVisitor
|
||||
#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor
|
||||
#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor
|
||||
|
||||
#endif // Guard
|
||||
+813
-73
File diff suppressed because it is too large
Load Diff
+3331
-889
File diff suppressed because it is too large
Load Diff
+184
-95
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Removal of named begin blocks
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -25,6 +24,9 @@
|
||||
// BEGIN(VAR...) -> VAR ... {renamed}
|
||||
// FOR -> WHILEs
|
||||
//
|
||||
// There are two scopes; named BEGINs change %m and variable scopes.
|
||||
// Unnamed BEGINs change only variable, not $display("%m") scope.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
@@ -42,13 +44,37 @@
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BeginState {
|
||||
private:
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// AstNodeFTask::user1 -> bool, 1=processed
|
||||
AstUser1InUse m_inuser1;
|
||||
bool m_anyFuncInBegin;
|
||||
public:
|
||||
BeginState() {
|
||||
m_anyFuncInBegin = false;
|
||||
}
|
||||
~BeginState() {}
|
||||
void userMarkChanged(AstNode* nodep) {
|
||||
nodep->user1(true);
|
||||
m_anyFuncInBegin = true;
|
||||
}
|
||||
bool anyFuncInBegin() const { return m_anyFuncInBegin; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BeginVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstModule* m_modp; // Current module
|
||||
BeginState* m_statep; // Current global state
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstNodeFTask* m_ftaskp; // Current function/task
|
||||
string m_beginScope; // Name of begin blocks above us
|
||||
string m_namedScope; // Name of begin blocks above us
|
||||
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
|
||||
int m_repeatNum; // Repeat counter
|
||||
int m_ifDepth; // Current if depth
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -58,154 +84,217 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
m_repeatNum = 0;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
|
||||
m_ftaskp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_ftaskp = NULL;
|
||||
virtual void visit(AstNodeFTask* nodep) {
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
// Rename it
|
||||
if (m_unnamedScope != "") {
|
||||
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
|
||||
UINFO(8," rename to "<<nodep->name()<<endl);
|
||||
m_statep->userMarkChanged(nodep);
|
||||
}
|
||||
// BEGIN wrapping a function rename that function, but don't affect the inside function's variables
|
||||
// We then restart with empty naming; so that any begin's inside the function will rename inside the function
|
||||
// Process children
|
||||
string oldScope = m_namedScope;
|
||||
string oldUnnamed = m_unnamedScope;
|
||||
{
|
||||
m_namedScope = "";
|
||||
m_unnamedScope = "";
|
||||
m_ftaskp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_ftaskp = NULL;
|
||||
}
|
||||
m_namedScope = oldScope;
|
||||
m_unnamedScope = oldUnnamed;
|
||||
}
|
||||
virtual void visit(AstBegin* nodep, AstNUser*) {
|
||||
virtual void visit(AstBegin* nodep) {
|
||||
// Begin blocks were only useful in variable creation, change names and delete
|
||||
UINFO(8," "<<nodep<<endl);
|
||||
string oldScope = m_beginScope;
|
||||
string oldScope = m_namedScope;
|
||||
string oldUnnamed = m_unnamedScope;
|
||||
{
|
||||
//UINFO(8,"nname "<<m_beginScope<<endl);
|
||||
// Create data for dotted variable resolution
|
||||
string dottedname = nodep->name() + "__DOT__"; // So always found
|
||||
string::size_type pos;
|
||||
while ((pos=dottedname.find("__DOT__")) != string::npos) {
|
||||
string ident = dottedname.substr(0,pos);
|
||||
dottedname = dottedname.substr(pos+strlen("__DOT__"));
|
||||
if (m_beginScope=="") m_beginScope = ident;
|
||||
else m_beginScope = m_beginScope + "__DOT__"+ident;
|
||||
// Create CellInline for dotted resolution
|
||||
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
|
||||
m_beginScope, "__BEGIN__");
|
||||
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
|
||||
UINFO(8,"nname "<<m_namedScope<<endl);
|
||||
if (nodep->name() != "") { // Else unneeded unnamed block
|
||||
// Create data for dotted variable resolution
|
||||
string dottedname = nodep->name() + "__DOT__"; // So always found
|
||||
string::size_type pos;
|
||||
while ((pos=dottedname.find("__DOT__")) != string::npos) {
|
||||
string ident = dottedname.substr(0,pos);
|
||||
dottedname = dottedname.substr(pos+strlen("__DOT__"));
|
||||
if (!nodep->unnamed()) {
|
||||
if (m_namedScope=="") m_namedScope = ident;
|
||||
else m_namedScope = m_namedScope + "__DOT__"+ident;
|
||||
}
|
||||
if (m_unnamedScope=="") m_unnamedScope = ident;
|
||||
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
|
||||
// Create CellInline for dotted var resolution
|
||||
if (!m_ftaskp) {
|
||||
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
|
||||
m_unnamedScope, "__BEGIN__");
|
||||
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remap var names
|
||||
nodep->iterateChildren(*this);
|
||||
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
nodep->replaceWith(stmtsp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
pushDeletep(nodep); nodep=NULL;
|
||||
// Remap var names and replace lower Begins
|
||||
nodep->stmtsp()->iterateAndNext(*this);
|
||||
if (nodep->genforp()) nodep->v3fatalSrc("GENFORs should have been expanded earlier");
|
||||
}
|
||||
m_beginScope = oldScope;
|
||||
m_namedScope = oldScope;
|
||||
m_unnamedScope = oldUnnamed;
|
||||
|
||||
// Cleanup
|
||||
AstNode* addsp = NULL;
|
||||
if (AstNode* stmtsp = nodep->stmtsp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; }
|
||||
}
|
||||
if (addsp) {
|
||||
nodep->replaceWith(addsp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
pushDeletep(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {
|
||||
if (m_beginScope != "") {
|
||||
virtual void visit(AstVar* nodep) {
|
||||
if (m_unnamedScope != "") {
|
||||
// Rename it
|
||||
nodep->name(m_beginScope+"__DOT__"+nodep->name());
|
||||
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
|
||||
m_statep->userMarkChanged(nodep);
|
||||
// Move to module
|
||||
nodep->unlinkFrBack();
|
||||
if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
|
||||
else m_modp->addStmtp(nodep);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCell* nodep, AstNUser*) {
|
||||
virtual void visit(AstCell* nodep) {
|
||||
UINFO(8," CELL "<<nodep<<endl);
|
||||
if (m_beginScope != "") {
|
||||
if (m_namedScope != "") {
|
||||
m_statep->userMarkChanged(nodep);
|
||||
// Rename it
|
||||
nodep->name(m_beginScope+"__DOT__"+nodep->name());
|
||||
nodep->name(m_namedScope+"__DOT__"+nodep->name());
|
||||
UINFO(8," rename to "<<nodep->name()<<endl);
|
||||
// Move to module
|
||||
nodep->unlinkFrBack();
|
||||
m_modp->addStmtp(nodep);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstFor* nodep, AstNUser*) {
|
||||
// So later optimizations don't need to deal with them,
|
||||
// FOR(init,cond,assign,body) -> init,WHILE(cond) { body, assign }
|
||||
AstNode* initsp = nodep->initsp(); if (initsp) initsp->unlinkFrBackWithNext();
|
||||
AstNode* condp = nodep->condp(); if (condp) condp->unlinkFrBackWithNext();
|
||||
AstNode* incsp = nodep->incsp(); if (incsp) incsp->unlinkFrBackWithNext();
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
bodysp = bodysp->addNext(incsp);
|
||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||
condp,
|
||||
bodysp);
|
||||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstRepeat* nodep, AstNUser*) {
|
||||
// So later optimizations don't need to deal with them,
|
||||
// REPEAT(count,body) -> loop=count,WHILE(loop>0) { body, loop-- }
|
||||
// Note var can be signed or unsigned based on original number.
|
||||
AstNode* countp = nodep->countp()->unlinkFrBackWithNext();
|
||||
string name = string("__Vrepeat")+cvtToStr(m_repeatNum++);
|
||||
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
|
||||
new AstRange(nodep->fileline(), countp->width()-1, 0));
|
||||
m_modp->addStmtp(varp);
|
||||
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
countp);
|
||||
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
|
||||
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 1)));
|
||||
AstNode* condp;
|
||||
if (countp->isSigned()) {
|
||||
condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
} else {
|
||||
condp = new AstGt (nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
|
||||
new AstConst(nodep->fileline(), 0));
|
||||
virtual void visit(AstVarXRef* nodep) {
|
||||
UINFO(9, " VARXREF "<<nodep<<endl);
|
||||
if (m_namedScope != "" && nodep->inlinedDots() == "") {
|
||||
nodep->inlinedDots(m_namedScope);
|
||||
UINFO(9, " rescope to "<<nodep<<endl);
|
||||
}
|
||||
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();
|
||||
bodysp = bodysp->addNext(decp);
|
||||
AstNode* newp = new AstWhile(nodep->fileline(),
|
||||
condp,
|
||||
bodysp);
|
||||
initsp = initsp->addNext(newp);
|
||||
newp = initsp;
|
||||
nodep->replaceWith(newp);
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||
virtual void visit(AstScopeName* nodep) {
|
||||
// If there's a %m in the display text, we add a special node that will contain the name()
|
||||
// Similar code in V3Inline
|
||||
if (m_beginScope != "") {
|
||||
if (nodep->user1SetOnce()) return; // Don't double-add text's
|
||||
if (m_namedScope != "") {
|
||||
// To keep correct visual order, must add before other Text's
|
||||
AstNode* afterp = nodep->scopeAttrp();
|
||||
if (afterp) afterp->unlinkFrBackWithNext();
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"."+AstNode::prettyName(m_beginScope)));
|
||||
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_namedScope));
|
||||
if (afterp) nodep->scopeAttrp(afterp);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
|
||||
virtual void visit(AstCoverDecl* nodep) {
|
||||
// Don't need to fix path in coverage statements, they're not under
|
||||
// any BEGINs, but V3Coverage adds them all under the module itself.
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// VISITORS - LINT CHECK
|
||||
virtual void visit(AstIf* nodep) { // Note not AstNodeIf; other types don't get covered
|
||||
// Check IFDEPTH warning - could be in other transform files if desire
|
||||
int prevIfDepth = m_ifDepth;
|
||||
if (m_ifDepth == -1 || v3Global.opt.ifDepth()<1) { // Turned off
|
||||
} else if (nodep->uniquePragma() || nodep->unique0Pragma() || nodep->priorityPragma()) {
|
||||
m_ifDepth = -1;
|
||||
} else if (++m_ifDepth > v3Global.opt.ifDepth()) {
|
||||
nodep->v3warn(IFDEPTH,"Deep 'if' statement; suggest unique/priority to avoid slow logic");
|
||||
nodep->fileline()->modifyWarnOff(V3ErrorCode::IFDEPTH, true); // Warn only once
|
||||
m_ifDepth = -1;
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
m_ifDepth = prevIfDepth;
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
BeginVisitor(AstNetlist* nodep) {
|
||||
BeginVisitor(AstNetlist* nodep, BeginState* statep) {
|
||||
m_statep = statep;
|
||||
m_modp = NULL;
|
||||
m_ftaskp = NULL;
|
||||
m_repeatNum = 0;
|
||||
m_ifDepth = 0;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~BeginVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BeginRelinkVisitor : public AstNVisitor {
|
||||
// Replace tasks with new pointer
|
||||
private:
|
||||
// NODE STATE
|
||||
// Input:
|
||||
// AstNodeFTask::user1p // Node replaced, rename it
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeFTaskRef* nodep) {
|
||||
if (nodep->taskp()->user1()) { // It was converted
|
||||
UINFO(9, " relinkFTask "<<nodep<<endl);
|
||||
nodep->name(nodep->taskp()->name());
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
if (nodep->varp()->user1()) { // It was converted
|
||||
UINFO(9, " relinVarRef "<<nodep<<endl);
|
||||
nodep->name(nodep->varp()->name());
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstIfaceRefDType* nodep) {
|
||||
// May have changed cell names
|
||||
// TypeTable is always after all modules, so names are stable
|
||||
UINFO(8," IFACEREFDTYPE "<<nodep<<endl);
|
||||
if (nodep->cellp()) nodep->cellName(nodep->cellp()->name());
|
||||
UINFO(8," rename to "<<nodep<<endl);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
BeginRelinkVisitor(AstNetlist* nodep, BeginState*) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~BeginRelinkVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Task class functions
|
||||
|
||||
void V3Begin::debeginAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
BeginVisitor bvisitor (nodep);
|
||||
BeginState state;
|
||||
{ BeginVisitor bvisitor (nodep,&state); }
|
||||
if (state.anyFuncInBegin()) {
|
||||
BeginRelinkVisitor brvisitor (nodep,&state);
|
||||
}
|
||||
V3Global::dumpCheckGlobalTree("begin", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Removal of named begin blocks
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+48
-14
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Branch prediction
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -22,6 +21,9 @@
|
||||
// At each IF/(IF else).
|
||||
// Count underneath $display/$stop statements.
|
||||
// If more on if than else, this branch is unlikely, or vice-versa.
|
||||
// At each FTASKREF,
|
||||
// Count calls into the function
|
||||
// Then, if FTASK is called only once, add inline attribute
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
@@ -41,9 +43,18 @@
|
||||
|
||||
class BranchVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstFTask::user1() -> int. Number of references
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// TYPES
|
||||
typedef vector<AstCFunc*> CFuncVec;
|
||||
|
||||
// STATE
|
||||
int m_likely; // Excuses for branch likely taken
|
||||
int m_unlikely; // Excuses for branch likely not taken
|
||||
CFuncVec m_cfuncsp; // List of all tasks
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -56,9 +67,15 @@ private:
|
||||
m_likely = false;
|
||||
m_unlikely = false;
|
||||
}
|
||||
void checkUnlikely(AstNode* nodep) {
|
||||
if (nodep->isUnlikely()) {
|
||||
UINFO(4," UNLIKELY: "<<nodep<<endl);
|
||||
m_unlikely++;
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
UINFO(4," IF: "<<nodep<<endl);
|
||||
int lastLikely = m_likely;
|
||||
int lastUnlikely = m_unlikely;
|
||||
@@ -76,28 +93,45 @@ private:
|
||||
// Compute
|
||||
int likeness = ifLikely - ifUnlikely - (elseLikely - elseUnlikely);
|
||||
if (likeness>0) {
|
||||
nodep->branchPred(AstBranchPred::LIKELY);
|
||||
nodep->branchPred(AstBranchPred::BP_LIKELY);
|
||||
} else if (likeness<0) {
|
||||
nodep->branchPred(AstBranchPred::UNLIKELY);
|
||||
nodep->branchPred(AstBranchPred::BP_UNLIKELY);
|
||||
} // else leave unknown
|
||||
}
|
||||
m_likely = lastLikely;
|
||||
m_unlikely = lastUnlikely;
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// Default: Just iterate
|
||||
if (nodep->isUnlikely()) {
|
||||
UINFO(4," UNLIKELY: "<<nodep<<endl);
|
||||
m_unlikely++;
|
||||
}
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
checkUnlikely(nodep);
|
||||
nodep->funcp()->user1Inc();
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
checkUnlikely(nodep);
|
||||
m_cfuncsp.push_back(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
checkUnlikely(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
// METHODS
|
||||
void calc_tasks() {
|
||||
for (CFuncVec::iterator it=m_cfuncsp.begin(); it!=m_cfuncsp.end(); ++it) {
|
||||
AstCFunc* nodep = *it;
|
||||
if (!nodep->dontInline()) {
|
||||
nodep->isInline(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
BranchVisitor(AstNetlist* rootp) {
|
||||
explicit BranchVisitor(AstNetlist* nodep) {
|
||||
reset();
|
||||
rootp->iterateChildren(*this);
|
||||
nodep->iterateChildren(*this);
|
||||
calc_tasks();
|
||||
}
|
||||
virtual ~BranchVisitor() {}
|
||||
};
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Branch prediction
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+103
-36
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Find broken links in tree
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -38,6 +37,9 @@
|
||||
#include "V3Broken.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
|
||||
#include "V3AstConstOnly.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class BrokenTable : public AstNVisitor {
|
||||
@@ -48,30 +50,45 @@ private:
|
||||
typedef map<const AstNode*,int> NodeMap;
|
||||
static NodeMap s_nodes; // Set of all nodes that exist
|
||||
// BITMASK
|
||||
static const int FLAG_ALLOCATED = 0x01; // new() and not delete()ed
|
||||
static const int FLAG_IN_TREE = 0x02; // Is in netlist tree
|
||||
static const int FLAG_LINKABLE = 0x04; // Is in netlist tree, can be linked to
|
||||
static const int FLAG_LEAKED = 0x08; // Known to have been leaked
|
||||
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
|
||||
enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree
|
||||
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
|
||||
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
|
||||
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
|
||||
public:
|
||||
// METHODS
|
||||
static void deleted(const AstNode* nodep) {
|
||||
// Called by operator delete on any node - only if VL_LEAK_CHECKS
|
||||
if (debug()) cout<<"-nodeDel: "<<(void*)(nodep)<<endl;
|
||||
if (debug()>=9) cout<<"-nodeDel: "<<(void*)(nodep)<<endl;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter==s_nodes.end() || !(iter->second & FLAG_ALLOCATED)) {
|
||||
((AstNode*)(nodep))->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted\n");
|
||||
((AstNode*)(nodep))->v3fatalSrc("Deleting AstNode object that was never tracked or already deleted");
|
||||
}
|
||||
if (iter!=s_nodes.end()) s_nodes.erase(iter);
|
||||
}
|
||||
#if defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 4
|
||||
// GCC 4.4.* compiler warning bug, https://gcc.gnu.org/bugzilla/show_bug.cgi?id=39390
|
||||
# pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif
|
||||
static void addNewed(const AstNode* nodep) {
|
||||
// Called by operator new on any node - only if VL_LEAK_CHECKS
|
||||
if (debug()) cout<<"-nodeNew: "<<(void*)(nodep)<<endl;
|
||||
if (debug()>=9) cout<<"-nodeNew: "<<(void*)(nodep)<<endl;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter!=s_nodes.end() || (iter->second & FLAG_ALLOCATED)) {
|
||||
((AstNode*)(nodep))->v3fatalSrc("Newing AstNode object that is already allocated\n");
|
||||
nodep->v3fatalSrc("Newing AstNode object that is already allocated");
|
||||
}
|
||||
if (iter == s_nodes.end()) {
|
||||
s_nodes.insert(make_pair(nodep,FLAG_ALLOCATED));
|
||||
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2
|
||||
s_nodes.insert(make_pair(nodep,flags));
|
||||
}
|
||||
}
|
||||
static void setUnder(const AstNode* nodep, bool flag) {
|
||||
// Called by BrokenCheckVisitor when each node entered/exited
|
||||
if (!okIfLinkedTo(nodep)) return;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter!=s_nodes.end()) {
|
||||
iter->second &= ~FLAG_UNDER_NOW;
|
||||
if (flag) iter->second |= FLAG_UNDER_NOW;
|
||||
}
|
||||
}
|
||||
static void addInTree(AstNode* nodep, bool linkable) {
|
||||
@@ -81,16 +98,16 @@ public:
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter == s_nodes.end()) {
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated\n");
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
|
||||
#endif
|
||||
} else {
|
||||
if (!(iter->second & FLAG_ALLOCATED)) {
|
||||
#ifdef VL_LEAK_CHECKS
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated\n");
|
||||
nodep->v3fatalSrc("AstNode is in tree, but not allocated");
|
||||
#endif
|
||||
}
|
||||
if (iter->second & FLAG_IN_TREE) {
|
||||
nodep->v3fatalSrc("AstNode is already in tree at another location\n");
|
||||
nodep->v3fatalSrc("AstNode is already in tree at another location");
|
||||
}
|
||||
}
|
||||
int or_flags = FLAG_IN_TREE | (linkable?FLAG_LINKABLE:0);
|
||||
@@ -111,6 +128,14 @@ public:
|
||||
if (!(iter->second & FLAG_LINKABLE)) return false;
|
||||
return true;
|
||||
}
|
||||
static bool okIfBelow(const AstNode* nodep) {
|
||||
// Must be linked to and below current node
|
||||
if (!okIfLinkedTo(nodep)) return false;
|
||||
NodeMap::iterator iter = s_nodes.find(nodep);
|
||||
if (iter == s_nodes.end()) return false;
|
||||
if (!(iter->second & FLAG_UNDER_NOW)) return false;
|
||||
return true;
|
||||
}
|
||||
static void prepForTree() {
|
||||
#ifndef VL_LEAK_CHECKS
|
||||
s_nodes.clear();
|
||||
@@ -129,7 +154,7 @@ public:
|
||||
&& (it->first->backp() ? backs==1 : backs==0)) {
|
||||
// Use only AstNode::dump instead of the virtual one, as there
|
||||
// may be varp() and other cross links that are bad.
|
||||
if (debug()) {
|
||||
if (v3Global.opt.debugCheck()) {
|
||||
cerr<<"%Error: LeakedNode"<<(it->first->backp()?"Back: ":": ");
|
||||
((AstNode*)(it->first))->AstNode::dump(cerr);
|
||||
cerr<<endl;
|
||||
@@ -152,6 +177,10 @@ bool AstNode::brokeExists() const {
|
||||
// Called by node->broken() routines to do table lookup
|
||||
return BrokenTable::okIfLinkedTo(this);
|
||||
}
|
||||
bool AstNode::brokeExistsAbove() const {
|
||||
// Called by node->broken() routines to do table lookup
|
||||
return BrokenTable::okIfBelow(this);
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -161,14 +190,18 @@ private:
|
||||
// NODE STATE
|
||||
// Nothing! // This may be called deep inside other routines
|
||||
// // so userp and friends may not be used
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
// METHODS
|
||||
void processAndIterate(AstNode* nodep) {
|
||||
BrokenTable::addInTree(nodep, nodep->maybePointedTo());
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->iterateChildrenConst(*this);
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep) {
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
BrokenMarkVisitor(AstNetlist* nodep) {
|
||||
explicit BrokenMarkVisitor(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~BrokenMarkVisitor() {}
|
||||
@@ -179,23 +212,49 @@ public:
|
||||
|
||||
class BrokenCheckVisitor : public AstNVisitor {
|
||||
private:
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
if (nodep->broken()) {
|
||||
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)\n");
|
||||
void checkWidthMin(AstNode* nodep) {
|
||||
if (nodep->width() != nodep->widthMin()
|
||||
&& v3Global.widthMinUsage()==VWidthMinUsage::MATCHES_WIDTH) {
|
||||
nodep->v3fatalSrc("Width != WidthMin");
|
||||
}
|
||||
if (v3Global.assertWidthsSame()) {
|
||||
if (nodep->width() != nodep->widthMin()) {
|
||||
nodep->v3fatalSrc("Width != WidthMin\n");
|
||||
}
|
||||
if (!nodep->width() && nodep->castNodeMath()) {
|
||||
nodep->v3fatalSrc("Math node has no assigned width\n");
|
||||
}
|
||||
}
|
||||
void processAndIterate(AstNode* nodep) {
|
||||
BrokenTable::setUnder(nodep,true);
|
||||
if (const char* whyp=nodep->broken()) {
|
||||
nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo): "<<whyp);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->dtypep()) {
|
||||
if (!nodep->dtypep()->brokeExists()) { nodep->v3fatalSrc("Broken link in node->dtypep() to "<<(void*)nodep->dtypep()); }
|
||||
else if (!nodep->dtypep()->castNodeDType()) { nodep->v3fatalSrc("Non-dtype link in node->dtypep() to "<<(void*)nodep->dtypep()); }
|
||||
}
|
||||
if (v3Global.assertDTypesResolved()) {
|
||||
if (nodep->hasDType()) {
|
||||
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype on node with hasDType(): "<<nodep->prettyTypeName());
|
||||
} else {
|
||||
if (nodep->dtypep()) nodep->v3fatalSrc("DType on node without hasDType(): "<<nodep->prettyTypeName());
|
||||
}
|
||||
if (nodep->getChildDTypep()) nodep->v3fatalSrc("childDTypep() non-null on node after should have removed");
|
||||
if (AstNodeDType* dnodep = nodep->castNodeDType()) checkWidthMin(dnodep);
|
||||
}
|
||||
checkWidthMin(nodep);
|
||||
nodep->iterateChildrenConst(*this);
|
||||
BrokenTable::setUnder(nodep,false);
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
processAndIterate(nodep);
|
||||
if (v3Global.assertDTypesResolved()
|
||||
&& nodep->brokeLhsMustBeLvalue()
|
||||
&& nodep->lhsp()->castNodeVarRef()
|
||||
&& !nodep->lhsp()->castNodeVarRef()->lvalue()) {
|
||||
nodep->v3fatalSrc("Assignment LHS is not an lvalue");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
processAndIterate(nodep);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
BrokenCheckVisitor(AstNetlist* nodep) {
|
||||
explicit BrokenCheckVisitor(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~BrokenCheckVisitor() {}
|
||||
@@ -206,10 +265,18 @@ public:
|
||||
|
||||
void V3Broken::brokenAll(AstNetlist* nodep) {
|
||||
//UINFO(9,__FUNCTION__<<": "<<endl);
|
||||
BrokenTable::prepForTree();
|
||||
BrokenMarkVisitor mvisitor (nodep);
|
||||
BrokenCheckVisitor cvisitor (nodep);
|
||||
BrokenTable::doneWithTree();
|
||||
static bool inBroken = false;
|
||||
if (inBroken) {
|
||||
// A error called by broken can recurse back into broken; avoid this
|
||||
UINFO(1,"Broken called under broken, skipping recursion.\n");
|
||||
} else {
|
||||
inBroken = true;
|
||||
BrokenTable::prepForTree();
|
||||
BrokenMarkVisitor mvisitor (nodep);
|
||||
BrokenCheckVisitor cvisitor (nodep);
|
||||
BrokenTable::doneWithTree();
|
||||
inBroken = false;
|
||||
}
|
||||
}
|
||||
|
||||
void V3Broken::addNewed(AstNode* nodep) {
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Find broken links in tree
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
@@ -0,0 +1,123 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Generate C language constructors and AstCReset nodes.
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3CCtors's Transformations:
|
||||
// Iterates over all modules and
|
||||
// for all AstVar, create a creates a AstCReset node in an _ctor_var_reset AstCFunc.
|
||||
// for all AstCoverDecl, move the declaration into a _configure_coverage AstCFunc.
|
||||
// For each variable that needs reset, add a AstCReset node.
|
||||
//
|
||||
// This transformation honors outputSplitCFuncs.
|
||||
//*************************************************************************
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <cmath>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3EmitCBase.h"
|
||||
#include "V3CCtors.h"
|
||||
|
||||
class V3CCtorsVisitor {
|
||||
private:
|
||||
string m_basename;
|
||||
string m_argsp;
|
||||
string m_callargsp;
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_tlFuncp; // Top level function being built
|
||||
AstCFunc* m_funcp; // Current function
|
||||
int m_numStmts; // Number of statements output
|
||||
int m_funcNum; // Function number being built
|
||||
|
||||
public:
|
||||
void add(AstNode* nodep) {
|
||||
if (v3Global.opt.outputSplitCFuncs()
|
||||
&& v3Global.opt.outputSplitCFuncs() < m_numStmts) {
|
||||
m_funcp = NULL;
|
||||
}
|
||||
if (!m_funcp) {
|
||||
m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum), NULL, "void");
|
||||
m_funcp->isStatic(false);
|
||||
m_funcp->declPrivate(true);
|
||||
m_funcp->slow(true);
|
||||
m_funcp->argTypes(m_argsp);
|
||||
m_modp->addStmtp(m_funcp);
|
||||
|
||||
// Add a top call to it
|
||||
AstCCall* callp = new AstCCall(m_modp->fileline(), m_funcp);
|
||||
callp->argTypes(m_callargsp);
|
||||
|
||||
m_tlFuncp->addStmtsp(callp);
|
||||
m_numStmts = 0;
|
||||
}
|
||||
m_funcp->addStmtsp(nodep);
|
||||
m_numStmts += 1;
|
||||
}
|
||||
|
||||
V3CCtorsVisitor(AstNodeModule* nodep, string basename, string argsp="", string callargsp="",
|
||||
const string& stmt="") {
|
||||
m_basename = basename;
|
||||
m_argsp = argsp;
|
||||
m_callargsp = callargsp;
|
||||
m_modp = nodep;
|
||||
m_numStmts = 0;
|
||||
m_funcNum = 0;
|
||||
m_tlFuncp = new AstCFunc(nodep->fileline(), basename, NULL, "void");
|
||||
m_tlFuncp->declPrivate(true);
|
||||
m_tlFuncp->isStatic(false);
|
||||
m_tlFuncp->slow(true);
|
||||
m_tlFuncp->argTypes(m_argsp);
|
||||
if (stmt != "") {
|
||||
m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt));
|
||||
}
|
||||
m_funcp = m_tlFuncp;
|
||||
m_modp->addStmtp(m_tlFuncp);
|
||||
}
|
||||
~V3CCtorsVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
void V3CCtors::cctorsAll() {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
|
||||
// Process each module in turn
|
||||
V3CCtorsVisitor var_reset (modp, "_ctor_var_reset");
|
||||
V3CCtorsVisitor configure_coverage (modp, "_configure_coverage",
|
||||
EmitCBaseVisitor::symClassVar()+ ", bool first", "vlSymsp, first",
|
||||
"if (0 && vlSymsp && first) {} // Prevent unused\n");
|
||||
|
||||
for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) {
|
||||
AstVar* varp = np->castVar();
|
||||
if (varp) var_reset.add(new AstCReset(varp->fileline(), new AstVarRef(varp->fileline(), varp, true)));
|
||||
AstCoverDecl* coverp = np->castCoverDecl();
|
||||
if (coverp) {
|
||||
AstNode* backp = coverp->backp();
|
||||
coverp->unlinkFrBack();
|
||||
configure_coverage.add(coverp);
|
||||
np = backp;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Signed/unsigned resolution
|
||||
// DESCRIPTION: Verilator: Emit CFunc's for class construction and configuration
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2005-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -20,8 +18,8 @@
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3SIGNED_H_
|
||||
#define _V3SIGNED_H_ 1
|
||||
#ifndef _V3CCTORS_H_
|
||||
#define _V3CCTORS_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
@@ -29,10 +27,10 @@
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Signed {
|
||||
class V3CCtors {
|
||||
public:
|
||||
static void signedAll(AstNetlist* nodep);
|
||||
static void signedParams(AstNode* nodep);
|
||||
static void cctorsAll();
|
||||
};
|
||||
|
||||
|
||||
#endif // Guard
|
||||
+60
-46
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break case statements up and add Unknown assigns
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -66,7 +65,10 @@ private:
|
||||
return level;
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeCase* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeCase* nodep) {
|
||||
if (nodep->castCase() && nodep->castCase()->casex()) {
|
||||
nodep->v3warn(CASEX,"Suggest casez (with ?'s) in place of casex (with X's)");
|
||||
}
|
||||
// Detect multiple defaults
|
||||
bool hitDefault = false;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
@@ -88,14 +90,15 @@ private:
|
||||
m_caseExprp = NULL;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||
virtual void visit(AstConst* nodep) {
|
||||
// See also neverItem
|
||||
if (m_caseExprp && nodep->num().isFourState()) {
|
||||
if (m_caseExprp->castGenCase()) {
|
||||
nodep->v3error("Use of x/? constant in generate case statement, (no such thing as 'generate casez')");
|
||||
} else if (m_caseExprp->castCase() && m_caseExprp->castCase()->casex()) {
|
||||
// Don't sweat it, we already complained about casex in general
|
||||
} else if (m_caseExprp->castCase() && m_caseExprp->castCase()->casez()) {
|
||||
} else if (m_caseExprp->castCase() && (m_caseExprp->castCase()->casez()
|
||||
|| m_caseExprp->castCase()->caseInside())) {
|
||||
if (nodep->num().isUnknown()) {
|
||||
nodep->v3warn(CASEWITHX, "Use of x constant in casez statement, (perhaps intended ?/z in constant)");
|
||||
}
|
||||
@@ -104,12 +107,12 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CaseLintVisitor(AstNodeCase* nodep) {
|
||||
explicit CaseLintVisitor(AstNodeCase* nodep) {
|
||||
m_caseExprp = NULL;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
@@ -133,7 +136,7 @@ private:
|
||||
// Per-CASE
|
||||
int m_caseWidth; // Width of valueItems
|
||||
int m_caseItems; // Number of caseItem unique values
|
||||
int m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
|
||||
bool m_caseNoOverlapsAllCovered; // Proven to be synopsys parallel_case compliant
|
||||
AstNode* m_valueItem[1<<CASE_OVERLAP_WIDTH]; // For each possible value, the case branch we need
|
||||
|
||||
// METHODS
|
||||
@@ -145,17 +148,19 @@ private:
|
||||
|
||||
bool isCaseTreeFast(AstCase* nodep) {
|
||||
int width = 0;
|
||||
bool opaque = false;
|
||||
m_caseItems = 0;
|
||||
m_caseNoOverlapsAllCovered = true;
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
|
||||
if (icondp->width() > width) width = icondp->width();
|
||||
if (icondp->isDouble()) opaque = true;
|
||||
if (!icondp->castConst()) width = CASE_BARF; // Can't parse; not a constant
|
||||
m_caseItems++;
|
||||
}
|
||||
}
|
||||
m_caseWidth = width;
|
||||
if (width==0 || width > CASE_OVERLAP_WIDTH) {
|
||||
if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) {
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
return false; // Too wide for analysis
|
||||
}
|
||||
@@ -169,7 +174,7 @@ private:
|
||||
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
|
||||
//if (debug()>=9) icondp->dumpTree(cout," caseitem: ");
|
||||
AstConst* iconstp = icondp->castConst();
|
||||
if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this\n");
|
||||
if (!iconstp) nodep->v3fatalSrc("above 'can't parse' should have caught this");
|
||||
if (neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
} else {
|
||||
@@ -192,7 +197,7 @@ private:
|
||||
}
|
||||
}
|
||||
}
|
||||
// Defaults were moved to last in the caseitem list by V3Link
|
||||
// Defaults were moved to last in the caseitem list by V3LinkDot
|
||||
if (itemp->isDefault()) { // Case statement's default... Fill the table
|
||||
for (uint32_t i=0; i<(1UL<<m_caseWidth); i++) {
|
||||
if (!m_valueItem[i]) m_valueItem[i] = itemp;
|
||||
@@ -241,7 +246,7 @@ private:
|
||||
if (m_valueItem[a] != m_valueItem[b]) { same=false; break; }
|
||||
}
|
||||
if (same) {
|
||||
tree1p->deleteTree(); tree1p=NULL;
|
||||
tree1p->deleteTree(); VL_DANGLING(tree1p);
|
||||
return tree0p;
|
||||
}
|
||||
|
||||
@@ -290,8 +295,8 @@ private:
|
||||
|
||||
if (ifrootp) nodep->replaceWith(ifrootp);
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
cexprp->deleteTree(); cexprp=NULL;
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
cexprp->deleteTree(); VL_DANGLING(cexprp);
|
||||
if (debug()>=9) ifrootp->dumpTree(cout," _simp: ");
|
||||
}
|
||||
|
||||
@@ -308,7 +313,7 @@ private:
|
||||
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
|
||||
if (!itemp->condsp()) {
|
||||
// Default clause. Just make true, we'll optimize it away later
|
||||
itemp->condsp(new AstConst(itemp->fileline(), V3Number(itemp->fileline(), 1,1)));
|
||||
itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue()));
|
||||
hadDefault = true;
|
||||
} else {
|
||||
// Expressioned clause
|
||||
@@ -318,34 +323,42 @@ private:
|
||||
icondNextp = icondp->nextp();
|
||||
icondp->unlinkFrBack();
|
||||
|
||||
AstNode* and1p;
|
||||
AstNode* and2p;
|
||||
AstNode* condp = NULL; // Default is to use and1p/and2p
|
||||
AstConst* iconstp = icondp->castConst();
|
||||
if (iconstp && neverItem(nodep, iconstp)) {
|
||||
// X in casez can't ever be executed
|
||||
icondp->deleteTree(); icondp=NULL; iconstp=NULL;
|
||||
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
|
||||
// For simplicity, make expression that is not equal, and let later
|
||||
// optimizations remove it
|
||||
and1p = new AstConst(itemp->fileline(), V3Number(itemp->fileline(),1,0));
|
||||
and2p = new AstConst(itemp->fileline(), V3Number(itemp->fileline(),1,1));
|
||||
condp = new AstConst(itemp->fileline(), AstConst::LogicFalse());
|
||||
} else if (AstInsideRange* irangep = icondp->castInsideRange()) {
|
||||
// Similar logic in V3Width::visit(AstInside)
|
||||
AstNode* ap = AstGte::newTyped(itemp->fileline(),
|
||||
cexprp->cloneTree(false),
|
||||
irangep->lhsp()->unlinkFrBack());
|
||||
AstNode* bp = AstLte::newTyped(itemp->fileline(),
|
||||
cexprp->cloneTree(false),
|
||||
irangep->rhsp()->unlinkFrBack());
|
||||
condp = new AstAnd(itemp->fileline(), ap, bp);
|
||||
} else if (iconstp && iconstp->num().isFourState()
|
||||
&& (nodep->casex() || nodep->casez())) {
|
||||
&& (nodep->casex() || nodep->casez() || nodep->caseInside())) {
|
||||
V3Number nummask (itemp->fileline(), iconstp->width());
|
||||
nummask.opBitsNonX(iconstp->num());
|
||||
V3Number numval (itemp->fileline(), iconstp->width());
|
||||
numval.opBitsOne(iconstp->num());
|
||||
and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
and2p = new AstAnd(itemp->fileline(),
|
||||
new AstConst(itemp->fileline(), numval),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
icondp->deleteTree(); icondp=NULL; iconstp=NULL;
|
||||
AstNode* and1p = new AstAnd(itemp->fileline(), cexprp->cloneTree(false),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
AstNode* and2p = new AstAnd(itemp->fileline(),
|
||||
new AstConst(itemp->fileline(), numval),
|
||||
new AstConst(itemp->fileline(), nummask));
|
||||
icondp->deleteTree(); VL_DANGLING(icondp); VL_DANGLING(iconstp);
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
} else {
|
||||
// Not a caseX mask, we can simply build CASEEQ(cexpr icond)
|
||||
and1p = cexprp->cloneTree(false);
|
||||
and2p = icondp;
|
||||
AstNode* and1p = cexprp->cloneTree(false);
|
||||
AstNode* and2p = icondp;
|
||||
condp = AstEq::newTyped(itemp->fileline(), and1p, and2p);
|
||||
}
|
||||
AstEq* condp = new AstEq(itemp->fileline(), and1p, and2p);
|
||||
if (!ifexprp) {
|
||||
ifexprp = condp;
|
||||
} else {
|
||||
@@ -356,12 +369,12 @@ private:
|
||||
itemp->condsp(ifexprp);
|
||||
}
|
||||
}
|
||||
cexprp->deleteTree(); cexprp=NULL;
|
||||
cexprp->deleteTree(); VL_DANGLING(cexprp);
|
||||
if (!hadDefault) {
|
||||
// If there was no default, add a empty one, this greatly simplifies below code
|
||||
// and constant propagation will just eliminate it for us later.
|
||||
nodep->addItemsp(new AstCaseItem(nodep->fileline(),
|
||||
new AstConst(nodep->fileline(), V3Number(nodep->fileline(),1,1)),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicTrue()),
|
||||
NULL));
|
||||
}
|
||||
if (debug()>=9) nodep->dumpTree(cout," _comp_COND: ");
|
||||
@@ -395,10 +408,10 @@ private:
|
||||
}
|
||||
}
|
||||
{ // Make the new lower IF and attach in the tree
|
||||
AstNode* itemexprp = ifexprp; ifexprp=NULL;
|
||||
AstNode* itemexprp = ifexprp; VL_DANGLING(ifexprp);
|
||||
if (depth == (CASE_ENCODER_GROUP_DEPTH)) { // End of group - can skip the condition
|
||||
itemexprp->deleteTree(); itemexprp=NULL;
|
||||
itemexprp = new AstConst(itemp->fileline(), V3Number(itemp->fileline(),1,1));
|
||||
itemexprp->deleteTree(); VL_DANGLING(itemexprp);
|
||||
itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue());
|
||||
}
|
||||
AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, NULL);
|
||||
if (itemnextp) itemnextp->addElsesp(newp);
|
||||
@@ -410,10 +423,10 @@ private:
|
||||
// Handle any assertions
|
||||
replaceCaseParallel(nodep, false);
|
||||
// Replace the CASE... with IF...
|
||||
if (debug()>=9) grouprootp->dumpTree(cout," _new: ");
|
||||
if (debug()>=9 && grouprootp) grouprootp->dumpTree(cout," _new: ");
|
||||
if (grouprootp) nodep->replaceWith(grouprootp);
|
||||
else nodep->unlinkFrBack();
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
|
||||
void replaceCaseParallel(AstCase* nodep, bool noOverlapsAllCovered) {
|
||||
@@ -429,7 +442,7 @@ private:
|
||||
bool neverItem(AstCase* casep, AstConst* itemp) {
|
||||
// Xs in case or casez are impossible due to two state simulations
|
||||
if (casep->casex()) {
|
||||
} else if (casep->casez()) {
|
||||
} else if (casep->casez() || casep->caseInside()) {
|
||||
if (itemp->num().isUnknown()) return true;
|
||||
} else {
|
||||
if (itemp->num().isFourState()) return true;
|
||||
@@ -438,29 +451,29 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstCase* nodep, AstNUser*) {
|
||||
virtual void visit(AstCase* nodep) {
|
||||
V3Case::caseLint(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
if (debug()>=9) nodep->dumpTree(cout," case_old: ");
|
||||
if (isCaseTreeFast(nodep) && v3Global.opt.oCase()) {
|
||||
// It's a simple priority encoder or complete statement
|
||||
// we can make a tree of statements to avoid extra comparisons
|
||||
m_statCaseFast++;
|
||||
replaceCaseFast(nodep); nodep=NULL;
|
||||
++m_statCaseFast;
|
||||
replaceCaseFast(nodep); VL_DANGLING(nodep);
|
||||
} else {
|
||||
m_statCaseSlow++;
|
||||
replaceCaseComplicated(nodep); nodep=NULL;
|
||||
++m_statCaseSlow;
|
||||
replaceCaseComplicated(nodep); VL_DANGLING(nodep);
|
||||
}
|
||||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CaseVisitor(AstNetlist* nodep) {
|
||||
explicit CaseVisitor(AstNetlist* nodep) {
|
||||
m_caseNoOverlapsAllCovered = false;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
@@ -476,6 +489,7 @@ public:
|
||||
void V3Case::caseAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CaseVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("case", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
void V3Case::caseLint(AstNodeCase* nodep) {
|
||||
UINFO(4,__FUNCTION__<<": "<<endl);
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break case statements up and add Unknown assigns
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+18
-18
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Add C++ casts across expression size changes
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2004-2017 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.
|
||||
@@ -77,8 +76,7 @@ private:
|
||||
AstNRelinker relinkHandle;
|
||||
nodep->unlinkFrBack(&relinkHandle);
|
||||
//
|
||||
AstCast* castp = new AstCast (nodep->fileline(), nodep, needsize);
|
||||
castp->width(needsize, nodep->widthMin());
|
||||
AstCCast* castp = new AstCCast (nodep->fileline(), nodep, needsize, nodep->widthMin());
|
||||
relinkHandle.relink(castp);
|
||||
//if (debug()>8) castp->dumpTree(cout,"-castins: ");
|
||||
//
|
||||
@@ -97,31 +95,31 @@ private:
|
||||
insertCast(nodep, castSize(nodep->backp()));
|
||||
}
|
||||
}
|
||||
void insureLower32Cast(AstCast* nodep) {
|
||||
void insureLower32Cast(AstCCast* nodep) {
|
||||
// If we have uint64 = CAST(uint64(x)) then the upcasting
|
||||
// really needs to be CAST(uint64(CAST(uint32(x))).
|
||||
// Otherwise a (uint64)(a>b) would return wrong value, as
|
||||
// less than has undeterministic signedness.
|
||||
if (nodep->isQuad() && !nodep->lhsp()->isQuad()
|
||||
&& !nodep->lhsp()->castCast()) {
|
||||
&& !nodep->lhsp()->castCCast()) {
|
||||
insertCast(nodep->lhsp(), VL_WORDSIZE);
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeUniop* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeUniop* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeBiop* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user1(nodep->lhsp()->user1()
|
||||
| nodep->rhsp()->user1());
|
||||
if (nodep->sizeMattersLhs()) insureCast(nodep->lhsp());
|
||||
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
|
||||
}
|
||||
virtual void visit(AstNodeTriop* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeTriop* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user1(nodep->lhsp()->user1()
|
||||
| nodep->rhsp()->user1()
|
||||
@@ -130,12 +128,12 @@ private:
|
||||
if (nodep->sizeMattersRhs()) insureCast(nodep->rhsp());
|
||||
if (nodep->sizeMattersThs()) insureCast(nodep->thsp());
|
||||
}
|
||||
virtual void visit(AstCast* nodep, AstNUser*) {
|
||||
virtual void visit(AstCCast* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureLower32Cast(nodep);
|
||||
nodep->user1(1);
|
||||
}
|
||||
virtual void visit(AstUnaryMin* nodep, AstNUser*) {
|
||||
virtual void visit(AstNegate* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->lhsp()->widthMin()==1) {
|
||||
@@ -147,10 +145,11 @@ private:
|
||||
insureCast(nodep->lhsp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
if (!nodep->lvalue()
|
||||
&& !nodep->backp()->castCast()
|
||||
&& !nodep->backp()->castCCast()
|
||||
&& nodep->backp()->castNodeMath()
|
||||
&& !nodep->backp()->castArraySel()
|
||||
&& nodep->backp()->width()
|
||||
&& castSize(nodep) != castSize(nodep->varp())) {
|
||||
// Cast vars to IData first, else below has upper bits wrongly set
|
||||
@@ -159,7 +158,7 @@ private:
|
||||
}
|
||||
nodep->user1(1);
|
||||
}
|
||||
virtual void visit(AstConst* nodep, AstNUser*) {
|
||||
virtual void visit(AstConst* nodep) {
|
||||
// Constants are of unknown size if smaller than 33 bits, becase
|
||||
// we're too lazy to wrap every constant in the universe in
|
||||
// ((IData)#).
|
||||
@@ -167,17 +166,17 @@ private:
|
||||
}
|
||||
|
||||
// NOPs
|
||||
virtual void visit(AstVar* nodep, AstNUser*) {}
|
||||
virtual void visit(AstVar* nodep) {}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CastVisitor(AstNetlist* nodep) {
|
||||
explicit CastVisitor(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~CastVisitor() {}
|
||||
@@ -189,4 +188,5 @@ public:
|
||||
void V3Cast::castAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CastVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("cast", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Add C++ casts across expression size changes
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2004-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2004-2017 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.
|
||||
|
||||
+767
@@ -0,0 +1,767 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Clock Domain Crossing Lint
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3Cdc's Transformations:
|
||||
//
|
||||
// Create V3Graph-ish graph
|
||||
// Find all negedge reset flops
|
||||
// Trace back to previous flop
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
#include <iomanip>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <memory>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3Cdc.h"
|
||||
#include "V3Ast.h"
|
||||
#include "V3Graph.h"
|
||||
#include "V3Const.h"
|
||||
#include "V3EmitV.h"
|
||||
#include "V3File.h"
|
||||
|
||||
#define CDC_WEIGHT_ASYNC 0x1000 // Weight for edges that feed async logic
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcBaseVisitor : public AstNVisitor {
|
||||
public:
|
||||
static int debug() {
|
||||
static int level = -1;
|
||||
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
|
||||
return level;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Graph support classes
|
||||
|
||||
class CdcEitherVertex : public V3GraphVertex {
|
||||
AstScope* m_scopep;
|
||||
AstNode* m_nodep;
|
||||
AstSenTree* m_srcDomainp;
|
||||
AstSenTree* m_dstDomainp;
|
||||
bool m_srcDomainSet:1;
|
||||
bool m_dstDomainSet:1;
|
||||
bool m_asyncPath:1;
|
||||
public:
|
||||
CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep)
|
||||
: V3GraphVertex(graphp), m_scopep(scopep), m_nodep(nodep)
|
||||
, m_srcDomainp(NULL), m_dstDomainp(NULL)
|
||||
, m_srcDomainSet(false), m_dstDomainSet(false)
|
||||
, m_asyncPath(false) {}
|
||||
virtual ~CdcEitherVertex() {}
|
||||
// Accessors
|
||||
AstScope* scopep() const { return m_scopep; }
|
||||
AstNode* nodep() const { return m_nodep; }
|
||||
AstSenTree* srcDomainp() const { return m_srcDomainp; }
|
||||
void srcDomainp(AstSenTree* nodep) { m_srcDomainp = nodep; }
|
||||
bool srcDomainSet() const { return m_srcDomainSet; }
|
||||
void srcDomainSet(bool flag) { m_srcDomainSet = flag; }
|
||||
AstSenTree* dstDomainp() const { return m_dstDomainp; }
|
||||
void dstDomainp(AstSenTree* nodep) { m_dstDomainp = nodep; }
|
||||
bool dstDomainSet() const { return m_dstDomainSet; }
|
||||
void dstDomainSet(bool flag) { m_dstDomainSet = flag; }
|
||||
bool asyncPath() const { return m_asyncPath; }
|
||||
void asyncPath(bool flag) { m_asyncPath = flag; }
|
||||
};
|
||||
|
||||
class CdcVarVertex : public CdcEitherVertex {
|
||||
AstVarScope* m_varScp;
|
||||
int m_cntAsyncRst;
|
||||
bool m_fromFlop;
|
||||
public:
|
||||
CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
|
||||
: CdcEitherVertex(graphp, scopep, varScp), m_varScp(varScp), m_cntAsyncRst(0), m_fromFlop(false) {}
|
||||
virtual ~CdcVarVertex() {}
|
||||
// Accessors
|
||||
AstVarScope* varScp() const { return m_varScp; }
|
||||
virtual string name() const { return (cvtToStr((void*)m_varScp)+" "+varScp()->name()); }
|
||||
virtual string dotColor() const { return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; }
|
||||
int cntAsyncRst() const { return m_cntAsyncRst; }
|
||||
void cntAsyncRst(int flag) { m_cntAsyncRst=flag; }
|
||||
bool fromFlop() const { return m_fromFlop; }
|
||||
void fromFlop(bool flag) { m_fromFlop = flag; }
|
||||
};
|
||||
|
||||
class CdcLogicVertex : public CdcEitherVertex {
|
||||
bool m_hazard:1;
|
||||
bool m_isFlop:1;
|
||||
public:
|
||||
CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep)
|
||||
: CdcEitherVertex(graphp,scopep,nodep)
|
||||
, m_hazard(false), m_isFlop(false)
|
||||
{ srcDomainp(sensenodep); dstDomainp(sensenodep); }
|
||||
virtual ~CdcLogicVertex() {}
|
||||
// Accessors
|
||||
virtual string name() const { return (cvtToStr((void*)nodep())+"@"+scopep()->prettyName()); }
|
||||
virtual string dotColor() const { return hazard() ? "black" : "yellow"; }
|
||||
bool hazard() const { return m_hazard; }
|
||||
void setHazard(AstNode* nodep) { m_hazard = true; nodep->user3(true); }
|
||||
void clearHazard() { m_hazard = false; }
|
||||
bool isFlop() const { return m_isFlop; }
|
||||
void isFlop(bool flag) { m_isFlop = flag; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcDumpVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// {statement}Node::user3 -> bool, indicating not hazard
|
||||
ofstream* m_ofp; // Output file
|
||||
string m_prefix;
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
*m_ofp<<m_prefix;
|
||||
if (nodep->user3()) *m_ofp<<" %%";
|
||||
else *m_ofp<<" ";
|
||||
*m_ofp<<nodep->prettyTypeName()<<" "<<endl;
|
||||
string lastPrefix = m_prefix;
|
||||
m_prefix = lastPrefix + "1:";
|
||||
nodep->op1p()->iterateAndNext(*this);
|
||||
m_prefix = lastPrefix + "2:";
|
||||
nodep->op2p()->iterateAndNext(*this);
|
||||
m_prefix = lastPrefix + "3:";
|
||||
nodep->op3p()->iterateAndNext(*this);
|
||||
m_prefix = lastPrefix + "4:";
|
||||
nodep->op4p()->iterateAndNext(*this);
|
||||
m_prefix = lastPrefix;
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CdcDumpVisitor(AstNode* nodep, ofstream* ofp, const string& prefix) {
|
||||
m_ofp = ofp;
|
||||
m_prefix = prefix;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~CdcDumpVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
|
||||
class CdcWidthVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
int m_maxLineno;
|
||||
size_t m_maxFilenameLen;
|
||||
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Keeping line+filename lengths separate is much faster than calling ascii().length()
|
||||
if (nodep->fileline()->lineno() >= m_maxLineno) {
|
||||
m_maxLineno = nodep->fileline()->lineno()+1;
|
||||
}
|
||||
if (nodep->fileline()->filename().length() >= m_maxFilenameLen) {
|
||||
m_maxFilenameLen = nodep->fileline()->filename().length()+1;
|
||||
}
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
explicit CdcWidthVisitor(AstNode* nodep) {
|
||||
m_maxLineno = 0;
|
||||
m_maxFilenameLen = 0;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~CdcWidthVisitor() {}
|
||||
// ACCESSORS
|
||||
int maxWidth() {
|
||||
size_t width=1;
|
||||
width += m_maxFilenameLen;
|
||||
width += 1; // The :
|
||||
width += cvtToStr(m_maxLineno).length();
|
||||
width += 1; // Final :
|
||||
return (int)width;
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Cdc class functions
|
||||
|
||||
class CdcVisitor : public CdcBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
//Entire netlist:
|
||||
// AstVarScope::user1p -> CdcVarVertex* for usage var, 0=not set yet
|
||||
// AstVarScope::user2 -> bool Used in sensitivity list
|
||||
// {statement}Node::user1p -> CdcLogicVertex* for this statement
|
||||
// AstNode::user3 -> bool True indicates to print %% (via V3EmitV)
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// STATE
|
||||
V3Graph m_graph; // Scoreboard of var usages/dependencies
|
||||
CdcLogicVertex* m_logicVertexp; // Current statement being tracked, NULL=ignored
|
||||
AstScope* m_scopep; // Current scope being processed
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstSenTree* m_domainp; // Current sentree
|
||||
bool m_inDly; // In delayed assign
|
||||
int m_inSenItem; // Number of senitems
|
||||
string m_ofFilename; // Output filename
|
||||
ofstream* m_ofp; // Output file
|
||||
uint32_t m_userGeneration; // Generation count to avoid slow userClearVertices
|
||||
int m_filelineWidth; // Characters in longest fileline
|
||||
|
||||
// METHODS
|
||||
void iterateNewStmt(AstNode* nodep) {
|
||||
if (m_scopep) {
|
||||
UINFO(4," STMT "<<nodep<<endl);
|
||||
m_logicVertexp = new CdcLogicVertex(&m_graph, m_scopep, nodep, m_domainp);
|
||||
if (m_domainp && m_domainp->hasClocked()) { // To/from a flop
|
||||
m_logicVertexp->isFlop(true);
|
||||
m_logicVertexp->srcDomainp(m_domainp);
|
||||
m_logicVertexp->srcDomainSet(true);
|
||||
m_logicVertexp->dstDomainp(m_domainp);
|
||||
m_logicVertexp->dstDomainSet(true);
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
m_logicVertexp = NULL;
|
||||
|
||||
if (0 && debug()>=9) {
|
||||
UINFO(9, "Trace Logic:\n");
|
||||
nodep->dumpTree(cout, "-log1: ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CdcVarVertex* makeVarVertex(AstVarScope* varscp) {
|
||||
CdcVarVertex* vertexp = (CdcVarVertex*)(varscp->user1p());
|
||||
if (!vertexp) {
|
||||
UINFO(6,"New vertex "<<varscp<<endl);
|
||||
vertexp = new CdcVarVertex(&m_graph, m_scopep, varscp);
|
||||
varscp->user1p(vertexp);
|
||||
if (varscp->varp()->isUsedClock()) {}
|
||||
if (varscp->varp()->isPrimaryIO()) {
|
||||
// Create IO vertex - note it's relative to the pointed to var, not where we are now
|
||||
// This allows reporting to easily print the input statement
|
||||
CdcLogicVertex* ioVertexp = new CdcLogicVertex(&m_graph, varscp->scopep(), varscp->varp(), NULL);
|
||||
if (varscp->varp()->isInput()) {
|
||||
new V3GraphEdge(&m_graph, ioVertexp, vertexp, 1);
|
||||
} else {
|
||||
new V3GraphEdge(&m_graph, vertexp, ioVertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_inSenItem) {
|
||||
varscp->user2(true); // It's like a clock...
|
||||
// TODO: In the future we could mark it here and do normal clock tree glitch checks also
|
||||
} else if (varscp->user2()) { // It was detected in a sensitivity list earlier
|
||||
// And now it's used as logic. So must be a reset.
|
||||
vertexp->cntAsyncRst(vertexp->cntAsyncRst()+1);
|
||||
}
|
||||
return vertexp;
|
||||
}
|
||||
|
||||
void warnAndFile(AstNode* nodep, V3ErrorCode code, const string& msg) {
|
||||
static bool told_file = false;
|
||||
nodep->v3warnCode(code,msg);
|
||||
if (!told_file) {
|
||||
told_file = 1;
|
||||
cerr<<V3Error::msgPrefix()<<" See details in "<<m_ofFilename<<endl;
|
||||
}
|
||||
*m_ofp<<"%Warning-"<<code.ascii()<<": "<<nodep->fileline()<<" "<<msg<<endl;
|
||||
}
|
||||
|
||||
void setNodeHazard(AstNode* nodep) {
|
||||
// Need to not clear if warnings are off (rather than when report it)
|
||||
// as bypassing this warning may turn up another path that isn't warning off'ed.
|
||||
// We can't modifyWarnOff here, as one instantiation might not be an issue until we find a hitting flop
|
||||
// Furthermore, a module like a "Or" module would only get flagged once,
|
||||
// even though the signals feeding it are radically different.
|
||||
if (!m_domainp || m_domainp->hasCombo()) { // Source flop logic in a posedge block is OK for reset (not async though)
|
||||
if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) {
|
||||
UINFO(8,"Set hazard "<<nodep<<endl);
|
||||
m_logicVertexp->setHazard(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string spaces(int level) { string out; while (level--) out+=" "; return out; }
|
||||
|
||||
string pad(unsigned column, const string& in) {
|
||||
string out = in;
|
||||
while (out.length()<column) out += ' ';
|
||||
return out;
|
||||
}
|
||||
|
||||
void analyze() {
|
||||
UINFO(3,__FUNCTION__<<": "<<endl);
|
||||
//if (debug()>6) m_graph.dump();
|
||||
if (debug()>6) m_graph.dumpDotFilePrefixed("cdc_pre");
|
||||
//
|
||||
m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); // This will MAX across edge weights
|
||||
//
|
||||
m_graph.dumpDotFilePrefixed("cdc_simp");
|
||||
//
|
||||
analyzeReset();
|
||||
}
|
||||
|
||||
int filelineWidth() {
|
||||
if (!m_filelineWidth) {
|
||||
CdcWidthVisitor visitor (v3Global.rootp());
|
||||
m_filelineWidth = visitor.maxWidth();
|
||||
}
|
||||
return m_filelineWidth;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// RESET REPORT
|
||||
|
||||
void analyzeReset() {
|
||||
// Find all async reset wires, and trace backwards
|
||||
// userClearVertices is very slow, so we use a generation count instead
|
||||
m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
if (vvertexp->cntAsyncRst()) {
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
UINFO(8, " Trace One async: "<<vvertexp<<endl);
|
||||
// Twice, as we need to detect, then propagate
|
||||
CdcEitherVertex* markp = traceAsyncRecurse(vvertexp, false);
|
||||
if (markp) { // Mark is non-NULL if something bad on this path
|
||||
UINFO(9, " Trace One bad! "<<vvertexp<<endl);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
traceAsyncRecurse(vvertexp, true);
|
||||
m_userGeneration++; // Effectively a userClearVertices()
|
||||
dumpAsync(vvertexp, markp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) {
|
||||
// First pass: Return vertex of any hazardous stuff attached, or NULL if OK
|
||||
// If first pass returns true, second pass calls asyncPath() on appropriate nodes
|
||||
if (vertexp->user()>=m_userGeneration) return NULL; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
CdcEitherVertex* mark_outp = NULL;
|
||||
UINFO(9," Trace: "<<vertexp<<endl);
|
||||
|
||||
// Clear out in prep for marking next path
|
||||
if (!mark) vertexp->asyncPath(false);
|
||||
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Any logic considered bad, at the moment, anyhow
|
||||
if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp;
|
||||
// And keep tracing back so the user can understand what's up
|
||||
}
|
||||
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
if (mark) vvertexp->asyncPath(true);
|
||||
// If primary I/O, it's ok here back
|
||||
if (vvertexp->varScp()->varp()->isPrimaryIn()) {
|
||||
// Show the source "input" statement if it exists
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
// Also ok if from flop, but partially trace the flop so more obvious to users
|
||||
if (vvertexp->fromFlop()) {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
eFromVertexp->asyncPath(true);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
CdcEitherVertex* submarkp = traceAsyncRecurse(eFromVertexp, mark);
|
||||
if (submarkp && !mark_outp) mark_outp = submarkp;
|
||||
}
|
||||
|
||||
if (mark) vertexp->asyncPath(true);
|
||||
return mark_outp;
|
||||
}
|
||||
|
||||
void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) {
|
||||
AstNode* nodep = vertexp->varScp();
|
||||
*m_ofp<<"\n";
|
||||
*m_ofp<<"\n";
|
||||
CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many)
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* eToVertexp = (CdcEitherVertex*)edgep->top();
|
||||
if (!eToVertexp) targetp = eToVertexp;
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(eToVertexp)) {
|
||||
if (vvertexp->isFlop() // IE the target flop that is upsetting us
|
||||
&& edgep->weight() >= CDC_WEIGHT_ASYNC) { // And this signal feeds an async reset line
|
||||
targetp = eToVertexp;
|
||||
//UINFO(9," targetasync "<<targetp->name()<<" "<<" from "<<vertexp->name()<<endl);
|
||||
break;
|
||||
}
|
||||
} // else it might be random logic that's not relevant
|
||||
}
|
||||
//UINFO(9," finalflop "<<targetp->name()<<" "<<targetp->nodep()->fileline()<<endl);
|
||||
warnAndFile(markp->nodep(),V3ErrorCode::CDCRSTLOGIC,"Logic in path that feeds async reset, via signal: "+nodep->prettyName());
|
||||
dumpAsyncRecurse(targetp, "", " ",0);
|
||||
}
|
||||
bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep, int level) {
|
||||
// level=0 is special, indicates to dump destination flop
|
||||
// Return true if printed anything
|
||||
// If mark, also mark the output even if nothing hazardous below
|
||||
if (vertexp->user()>=m_userGeneration) return false; // Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
if (!vertexp->asyncPath() && level!=0) return false; // Not part of path
|
||||
|
||||
// Other logic in the path
|
||||
string cont = prefix+sep;
|
||||
string nextsep = " ";
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level+1)) {
|
||||
nextsep = " | ";
|
||||
}
|
||||
}
|
||||
|
||||
// Dump single variable/logic block
|
||||
// See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp)
|
||||
AstNode* nodep = vertexp->nodep();
|
||||
string front = pad(filelineWidth(),nodep->fileline()->ascii()+":")+" "+prefix+" +- ";
|
||||
if (nodep->castVarScope()) {
|
||||
*m_ofp<<front<<"Variable: "<<nodep->prettyName()<<endl;
|
||||
}
|
||||
else {
|
||||
V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix+" +- ", filelineWidth(),
|
||||
vertexp->srcDomainp(), true);
|
||||
if (debug()) {
|
||||
CdcDumpVisitor visitor (nodep, m_ofp, front+"DBG: ");
|
||||
}
|
||||
}
|
||||
|
||||
nextsep = " | ";
|
||||
if (level) *m_ofp<<V3OutFile::indentSpaces(filelineWidth())<<" "<<prefix<<nextsep<<"\n";
|
||||
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
// Now that we've printed a path with this hazard, don't bother to print any more
|
||||
// Otherwise, we'd get a path for almost every destination flop
|
||||
vvertexp->clearHazard();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------------------
|
||||
// EDGE REPORTS
|
||||
|
||||
void edgeReport() {
|
||||
// Make report of all signal names and what clock edges they have
|
||||
//
|
||||
// Due to flattening, many interesting direct-connect signals are
|
||||
// lost, so we can't make a report showing I/Os for a low level
|
||||
// module. Disabling flattening though makes us consider each
|
||||
// signal in it's own unique clock domain.
|
||||
|
||||
UINFO(3,__FUNCTION__<<": "<<endl);
|
||||
|
||||
// Trace all sources and sinks
|
||||
for (int traceDests=0; traceDests<2; ++traceDests) {
|
||||
UINFO(9, " Trace Direction "<<(traceDests?"dst":"src")<<endl);
|
||||
m_graph.userClearVertices(); // user1: bool - was analyzed
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
UINFO(9, " Trace One edge: "<<vvertexp<<endl);
|
||||
edgeDomainRecurse(vvertexp, traceDests, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc_edges.txt";
|
||||
const VL_UNIQUE_PTR<ofstream> ofp (V3File::new_ofstream(filename));
|
||||
if (ofp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
*ofp<<"Edge Report for "<<v3Global.opt.prefix()<<endl;
|
||||
|
||||
deque<string> report; // Sort output by name
|
||||
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
|
||||
if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(itp)) {
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
if (1) { // varp->isPrimaryIO()
|
||||
const char* whatp = "wire";
|
||||
if (varp->isPrimaryIO()) whatp = (varp->isInout()?"inout":varp->isInput()?"input":"output");
|
||||
|
||||
ostringstream os;
|
||||
os.setf(ios::left);
|
||||
// Module name - doesn't work due to flattening having lost the original
|
||||
// so we assume the modulename matches the filebasename
|
||||
string fname = vvertexp->varScp()->fileline()->filebasename() + ":";
|
||||
os<<" "<<setw(20)<<fname;
|
||||
os<<" "<<setw(8)<<whatp;
|
||||
os<<" "<<setw(40)<<vvertexp->varScp()->prettyName();
|
||||
os<<" SRC=";
|
||||
if (vvertexp->srcDomainp()) V3EmitV::verilogForTree(vvertexp->srcDomainp(), os);
|
||||
os<<" DST=";
|
||||
if (vvertexp->dstDomainp()) V3EmitV::verilogForTree(vvertexp->dstDomainp(), os);
|
||||
os<<setw(0);
|
||||
os<<endl;
|
||||
report.push_back(os.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
stable_sort(report.begin(), report.end());
|
||||
for (deque<string>::iterator it = report.begin(); it!=report.end(); ++it) {
|
||||
*ofp << *it;
|
||||
}
|
||||
}
|
||||
|
||||
void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) {
|
||||
// Scan back to inputs/outputs, flops, and compute clock domain information
|
||||
UINFO(8,spaces(level)<<" Tracein "<<vertexp<<endl);
|
||||
if (vertexp->user()>=m_userGeneration) return; // Mid-Processed - prevent loop
|
||||
vertexp->user(m_userGeneration);
|
||||
|
||||
// Variables from flops already are domained
|
||||
if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) return; // Fully computed
|
||||
|
||||
typedef set<AstSenTree*> SenSet;
|
||||
SenSet senouts; // List of all sensitivities for new signal
|
||||
if (CdcLogicVertex* vvertexp = dynamic_cast<CdcLogicVertex*>(vertexp)) {
|
||||
if (vvertexp) {} // Unused
|
||||
}
|
||||
else if (CdcVarVertex* vvertexp = dynamic_cast<CdcVarVertex*>(vertexp)) {
|
||||
// If primary I/O, give it domain of the input
|
||||
AstVar* varp = vvertexp->varScp()->varp();
|
||||
if (varp->isPrimaryIO() && varp->isInput() && !traceDests) {
|
||||
senouts.insert(new AstSenTree(varp->fileline(), new AstSenItem(varp->fileline(), AstSenItem::Combo())));
|
||||
}
|
||||
}
|
||||
|
||||
// Now combine domains of sources/dests
|
||||
if (traceDests) {
|
||||
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) {
|
||||
CdcEitherVertex* eToVertexp = (CdcEitherVertex*)edgep->top();
|
||||
edgeDomainRecurse(eToVertexp, traceDests, level+1);
|
||||
if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp());
|
||||
}
|
||||
} else {
|
||||
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
|
||||
CdcEitherVertex* eFromVertexp = (CdcEitherVertex*)edgep->fromp();
|
||||
edgeDomainRecurse(eFromVertexp, traceDests, level+1);
|
||||
if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp());
|
||||
}
|
||||
}
|
||||
|
||||
// Convert list of senses into one sense node
|
||||
AstSenTree* senoutp = NULL;
|
||||
bool senedited = false;
|
||||
for (SenSet::iterator it=senouts.begin(); it!=senouts.end(); ++it) {
|
||||
if (!senoutp) senoutp = *it;
|
||||
else {
|
||||
if (!senedited) {
|
||||
senedited = true;
|
||||
senoutp = senoutp->cloneTree(true);
|
||||
}
|
||||
senoutp->addSensesp((*it)->sensesp()->cloneTree(true));
|
||||
}
|
||||
}
|
||||
// If multiple domains need to do complicated optimizations
|
||||
if (senedited) {
|
||||
senoutp = V3Const::constifyExpensiveEdit(senoutp)->castSenTree();
|
||||
}
|
||||
if (traceDests) {
|
||||
vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->dstDomainp(senoutp);
|
||||
if (debug()>=9) {
|
||||
UINFO(9,spaces(level)+" Tracedst "<<vertexp);
|
||||
if (senoutp) { V3EmitV::verilogForTree(senoutp, cout); cout<<endl; }
|
||||
}
|
||||
} else {
|
||||
vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that
|
||||
vertexp->srcDomainp(senoutp);
|
||||
if (debug()>=9) {
|
||||
UINFO(9,spaces(level)+" Tracesrc "<<vertexp);
|
||||
if (senoutp) { V3EmitV::verilogForTree(senoutp, cout); cout<<endl; }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstScope* nodep) {
|
||||
UINFO(4," SCOPE "<<nodep<<endl);
|
||||
m_scopep = nodep;
|
||||
m_logicVertexp = NULL;
|
||||
nodep->iterateChildren(*this);
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
// Create required blocks and add to module
|
||||
UINFO(4," BLOCK "<<nodep<<endl);
|
||||
AstNode::user2ClearTree();
|
||||
m_domainp = nodep->sensesp();
|
||||
if (!m_domainp || m_domainp->hasCombo() || m_domainp->hasClocked()) { // IE not hasSettle/hasInitial
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
m_domainp = NULL;
|
||||
AstNode::user2ClearTree();
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep) {
|
||||
if (m_scopep) {
|
||||
if (!m_logicVertexp) nodep->v3fatalSrc("Var ref not under a logic block");
|
||||
AstVarScope* varscp = nodep->varScopep();
|
||||
if (!varscp) nodep->v3fatalSrc("Var didn't get varscoped in V3Scope.cpp");
|
||||
CdcVarVertex* varvertexp = makeVarVertex(varscp);
|
||||
UINFO(5," VARREF to "<<varscp<<endl);
|
||||
// We use weight of one for normal edges,
|
||||
// Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting)
|
||||
// When simplify we'll take the MAX weight
|
||||
if (nodep->lvalue()) {
|
||||
new V3GraphEdge(&m_graph, m_logicVertexp, varvertexp, 1);
|
||||
if (m_inDly) {
|
||||
varvertexp->fromFlop(true);
|
||||
varvertexp->srcDomainp(m_domainp);
|
||||
varvertexp->srcDomainSet(true);
|
||||
}
|
||||
} else {
|
||||
if (varvertexp->cntAsyncRst()) {
|
||||
//UINFO(9," edgeasync "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, CDC_WEIGHT_ASYNC);
|
||||
} else {
|
||||
//UINFO(9," edgena "<<varvertexp->name()<<" to "<<m_logicVertexp<<endl);
|
||||
new V3GraphEdge(&m_graph, varvertexp, m_logicVertexp, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstAssignDly* nodep) {
|
||||
m_inDly = true;
|
||||
nodep->iterateChildren(*this);
|
||||
m_inDly = false;
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
// Note we look at only AstSenItems, not AstSenGate's
|
||||
// The gating term of a AstSenGate is normal logic
|
||||
m_inSenItem = true;
|
||||
nodep->iterateChildren(*this);
|
||||
m_inSenItem = false;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPublic* nodep) {
|
||||
// CDC doesn't care about public variables
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstSenGate* nodep) {
|
||||
// First handle the clock part will be handled in a minute by visit AstSenItem
|
||||
// The logic gating term is delt with as logic
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignAlias* nodep) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
virtual void visit(AstAssignW* nodep) {
|
||||
iterateNewStmt(nodep);
|
||||
}
|
||||
|
||||
// Math that shouldn't cause us to clear hazard
|
||||
virtual void visit(AstConst* nodep) { }
|
||||
virtual void visit(AstReplicate* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstConcat* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNot* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstSel* nodep) {
|
||||
if (!nodep->lsbp()->castConst()) setNodeHazard(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNodeSel* nodep) {
|
||||
if (!nodep->bitp()->castConst()) setNodeHazard(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
// Ignores
|
||||
virtual void visit(AstInitial* nodep) { }
|
||||
virtual void visit(AstTraceInc* nodep) { }
|
||||
virtual void visit(AstCoverToggle* nodep) { }
|
||||
virtual void visit(AstNodeDType* nodep) { }
|
||||
|
||||
//--------------------
|
||||
// Default
|
||||
virtual void visit(AstNodeMath* nodep) {
|
||||
setNodeHazard(nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
explicit CdcVisitor(AstNode* nodep) {
|
||||
m_logicVertexp = NULL;
|
||||
m_scopep = NULL;
|
||||
m_modp = NULL;
|
||||
m_domainp = NULL;
|
||||
m_inDly = false;
|
||||
m_inSenItem = 0;
|
||||
m_userGeneration = 0;
|
||||
m_filelineWidth = 0;
|
||||
|
||||
// Make report of all signal names and what clock edges they have
|
||||
string filename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"__cdc.txt";
|
||||
m_ofp = V3File::new_ofstream(filename);
|
||||
if (m_ofp->fail()) v3fatalSrc("Can't write "<<filename);
|
||||
m_ofFilename = filename;
|
||||
*m_ofp<<"CDC Report for "<<v3Global.opt.prefix()<<endl;
|
||||
*m_ofp<<"Each dump below traces logic from inputs/source flops to destination flop(s).\n";
|
||||
*m_ofp<<"First source logic is listed, then a variable that logic generates,\n";
|
||||
*m_ofp<<"repeating recursively forwards to the destination flop(s).\n";
|
||||
*m_ofp<<"%% Indicates the operator considered potentially hazardous.\n";
|
||||
|
||||
nodep->accept(*this);
|
||||
analyze();
|
||||
if (debug()>=1) edgeReport(); // Not useful to users at the moment
|
||||
|
||||
if (0) { *m_ofp<<"\nDBG-test-dumper\n"; V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ",40,NULL,true); *m_ofp<<endl; }
|
||||
}
|
||||
virtual ~CdcVisitor() {
|
||||
if (m_ofp) { delete m_ofp; m_ofp = NULL; }
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Cdc class functions
|
||||
|
||||
void V3Cdc::cdcAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CdcVisitor visitor (nodep);
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into sensitivity block domains
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3CDC_H_
|
||||
#define _V3CDC_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3Cdc {
|
||||
public:
|
||||
static void cdcAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
+203
-57
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Add temporaries, such as for changed nodes
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -44,6 +43,176 @@
|
||||
#include "V3Changed.h"
|
||||
#include "V3EmitCBase.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class ChangedState {
|
||||
public:
|
||||
// STATE
|
||||
AstNodeModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
AstCFunc* m_chgFuncp; // Change function we're building
|
||||
AstCFunc* m_tlChgFuncp; // Top level change function we're building
|
||||
int m_numStmts; // Number of statements added to m_chgFuncp
|
||||
int m_funcNum; // Number of change functions emitted
|
||||
|
||||
ChangedState() {
|
||||
m_topModp = NULL;
|
||||
m_chgFuncp = NULL;
|
||||
m_scopetopp = NULL;
|
||||
m_tlChgFuncp = NULL;
|
||||
m_numStmts = 0;
|
||||
m_funcNum = 0;
|
||||
}
|
||||
~ChangedState() {}
|
||||
|
||||
void maybeCreateChgFuncp() {
|
||||
// Don't create an extra function call if splitting is disabled
|
||||
if (!v3Global.opt.outputSplitCFuncs()) {
|
||||
m_chgFuncp = m_tlChgFuncp;
|
||||
return;
|
||||
}
|
||||
if (!m_chgFuncp || v3Global.opt.outputSplitCFuncs() < m_numStmts) {
|
||||
m_chgFuncp = new AstCFunc(m_scopetopp->fileline(), "_change_request_" + cvtToStr(++m_funcNum), m_scopetopp, "QData");
|
||||
m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
m_chgFuncp->symProlog(true);
|
||||
m_chgFuncp->declPrivate(true);
|
||||
m_scopetopp->addActivep(m_chgFuncp);
|
||||
|
||||
// Add a top call to it
|
||||
AstCCall* callp = new AstCCall(m_scopetopp->fileline(), m_chgFuncp);
|
||||
callp->argTypes("vlSymsp");
|
||||
|
||||
if (!m_tlChgFuncp->stmtsp()) {
|
||||
m_tlChgFuncp->addStmtsp(new AstCReturn(m_scopetopp->fileline(), callp));
|
||||
} else {
|
||||
AstCReturn* returnp = m_tlChgFuncp->stmtsp()->castCReturn();
|
||||
if (!returnp) m_scopetopp->v3fatalSrc("Lost CReturn in top change function");
|
||||
// This is currently using AstLogOr which will shortcut the evaluation if
|
||||
// any function returns true. This is likely what we want and is similar to the logic already in use
|
||||
// inside V3EmitC, however, it also means that verbose logging may miss to print change detect variables.
|
||||
AstNode* newp = new AstCReturn(m_scopetopp->fileline(),
|
||||
new AstLogOr(m_scopetopp->fileline(), callp,
|
||||
returnp->lhsp()->unlinkFrBack()));
|
||||
returnp->replaceWith(newp);
|
||||
returnp->deleteTree(); VL_DANGLING(returnp);
|
||||
}
|
||||
m_numStmts = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Utility visitor to find elements to be compared
|
||||
|
||||
class ChangedInsertVisitor : public AstNVisitor {
|
||||
private:
|
||||
// STATE
|
||||
ChangedState* m_statep; // Shared state across visitors
|
||||
AstVarScope* m_vscp; // Original (non-change) variable we're change-detecting
|
||||
AstVarScope* m_newvscp; // New (change detect) variable we're change-detecting
|
||||
AstNode* m_varEqnp; // Original var's equation to get var value
|
||||
AstNode* m_newLvEqnp; // New var's equation to read value
|
||||
AstNode* m_newRvEqnp; // New var's equation to set value
|
||||
uint32_t m_detects; // # detects created
|
||||
|
||||
// CONSTANTS
|
||||
enum MiscConsts {
|
||||
DETECTARRAY_MAX_INDEXES = 256 // How many indexes before error
|
||||
// Ok to increase this, but may result in much slower model
|
||||
};
|
||||
|
||||
void newChangeDet() {
|
||||
if (++m_detects > DETECTARRAY_MAX_INDEXES) {
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
|
||||
<<" array indexes (probably with UNOPTFLAT warning suppressed): "<<m_vscp->prettyName()<<endl
|
||||
<<m_vscp->warnMore()
|
||||
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased"<<endl);
|
||||
return;
|
||||
}
|
||||
m_statep->maybeCreateChgFuncp();
|
||||
|
||||
AstChangeDet* changep = new AstChangeDet (m_vscp->fileline(),
|
||||
m_varEqnp->cloneTree(true),
|
||||
m_newRvEqnp->cloneTree(true), false);
|
||||
m_statep->m_chgFuncp->addStmtsp(changep);
|
||||
AstAssign* initp = new AstAssign (m_vscp->fileline(),
|
||||
m_newLvEqnp->cloneTree(true),
|
||||
m_varEqnp->cloneTree(true));
|
||||
m_statep->m_chgFuncp->addFinalsp(initp);
|
||||
EmitCBaseCounterVisitor visitor(initp);
|
||||
m_statep->m_numStmts += visitor.count();
|
||||
}
|
||||
|
||||
virtual void visit(AstBasicDType* nodep) {
|
||||
newChangeDet();
|
||||
}
|
||||
virtual void visit(AstPackArrayDType* nodep) {
|
||||
newChangeDet();
|
||||
}
|
||||
virtual void visit(AstUnpackArrayDType* nodep) {
|
||||
for (int index=0; index < nodep->elementsConst(); ++index) {
|
||||
AstNode* origVEp = m_varEqnp;
|
||||
AstNode* origNLEp = m_newLvEqnp;
|
||||
AstNode* origNREp = m_newRvEqnp;
|
||||
|
||||
m_varEqnp = new AstArraySel(nodep->fileline(), m_varEqnp->cloneTree(true), index);
|
||||
m_newLvEqnp = new AstArraySel(nodep->fileline(), m_newLvEqnp->cloneTree(true), index);
|
||||
m_newRvEqnp = new AstArraySel(nodep->fileline(), m_newRvEqnp->cloneTree(true), index);
|
||||
|
||||
nodep->subDTypep()->skipRefp()->accept(*this);
|
||||
|
||||
m_varEqnp->deleteTree();
|
||||
m_newLvEqnp->deleteTree();
|
||||
m_newRvEqnp->deleteTree();
|
||||
|
||||
m_varEqnp = origVEp;
|
||||
m_newLvEqnp = origNLEp;
|
||||
m_newRvEqnp = origNREp;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeClassDType* nodep) {
|
||||
if (nodep->packedUnsup()) {
|
||||
newChangeDet();
|
||||
} else {
|
||||
if (debug()) nodep->dumpTree(cout,"-DETECTARRAY-class-");
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<m_vscp->varp()->prettyName());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (debug()) nodep->dumpTree(cout,"-DETECTARRAY-general-");
|
||||
m_vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<m_vscp->varp()->prettyName());
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ChangedInsertVisitor(AstVarScope* vscp, ChangedState* statep) {
|
||||
m_statep = statep;
|
||||
m_vscp = vscp;
|
||||
m_detects = 0;
|
||||
{
|
||||
AstVar* varp = m_vscp->varp();
|
||||
string newvarname = "__Vchglast__"+m_vscp->scopep()->nameDotless()+"__"+varp->shortName();
|
||||
// Create: VARREF(_last)
|
||||
// ASSIGN(VARREF(_last), VARREF(var))
|
||||
// ...
|
||||
// CHANGEDET(VARREF(_last), VARREF(var))
|
||||
AstVar* newvarp = new AstVar (varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
|
||||
m_statep->m_topModp->addStmtp(newvarp);
|
||||
m_newvscp = new AstVarScope(m_vscp->fileline(), m_statep->m_scopetopp, newvarp);
|
||||
m_statep->m_scopetopp->addVarp(m_newvscp);
|
||||
|
||||
m_varEqnp = new AstVarRef(m_vscp->fileline(), m_vscp, false);
|
||||
m_newLvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, true);
|
||||
m_newRvEqnp = new AstVarRef(m_vscp->fileline(), m_newvscp, false);
|
||||
}
|
||||
vscp->dtypep()->skipRefp()->accept(*this);
|
||||
m_varEqnp->deleteTree();
|
||||
m_newLvEqnp->deleteTree();
|
||||
m_newRvEqnp->deleteTree();
|
||||
}
|
||||
virtual ~ChangedInsertVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Changed state, as a visitor of each AstNode
|
||||
|
||||
@@ -55,9 +224,7 @@ private:
|
||||
AstUser1InUse m_inuser1;
|
||||
|
||||
// STATE
|
||||
AstModule* m_topModp; // Top module
|
||||
AstScope* m_scopetopp; // Scope under TOPSCOPE
|
||||
AstCFunc* m_chgFuncp; // Change function we're building
|
||||
ChangedState* m_statep; // Shared state across visitors
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -67,85 +234,62 @@ private:
|
||||
}
|
||||
|
||||
void genChangeDet(AstVarScope* vscp) {
|
||||
#ifdef NEW_ORDERING
|
||||
vscp->v3fatalSrc("Not applicable\n");
|
||||
#endif
|
||||
AstVar* varp = vscp->varp();
|
||||
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
|
||||
if (varp->arraysp()) {
|
||||
vscp->v3error("Unsupported: Can't detect changes on arrayed variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
|
||||
} else {
|
||||
string newvarname = "__Vchglast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName();
|
||||
// Create: VARREF(_last)
|
||||
// ASSIGN(VARREF(_last), VARREF(var))
|
||||
// ...
|
||||
// CHANGEDET(VARREF(_last), VARREF(var))
|
||||
AstVar* newvarp = new AstVar (varp->fileline(), AstVarType::MODULETEMP, newvarname, varp);
|
||||
m_topModp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
|
||||
m_scopetopp->addVarp(newvscp);
|
||||
AstChangeDet* changep
|
||||
= new AstChangeDet (vscp->fileline(),
|
||||
new AstVarRef(vscp->fileline(), vscp, false),
|
||||
new AstVarRef(vscp->fileline(), newvscp, false),
|
||||
false);
|
||||
m_chgFuncp->addStmtsp(changep);
|
||||
AstAssign* initp
|
||||
= new AstAssign (vscp->fileline(),
|
||||
new AstVarRef(vscp->fileline(), newvscp, true),
|
||||
new AstVarRef(vscp->fileline(), vscp, false));
|
||||
m_chgFuncp->addFinalsp(initp);
|
||||
}
|
||||
ChangedInsertVisitor visitor (vscp, m_statep);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
if (nodep->isTop()) {
|
||||
m_topModp = nodep;
|
||||
m_statep->m_topModp = nodep;
|
||||
}
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstTopScope* nodep, AstNUser*) {
|
||||
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
UINFO(4," TS "<<nodep<<endl);
|
||||
// Clearing
|
||||
AstNode::user1ClearTree();
|
||||
// Create the change detection function
|
||||
AstScope* scopep = nodep->scopep();
|
||||
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n");
|
||||
m_scopetopp = scopep;
|
||||
// Create change detection function
|
||||
m_chgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "bool");
|
||||
m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
m_chgFuncp->symProlog(true);
|
||||
m_chgFuncp->declPrivate(true);
|
||||
m_scopetopp->addActivep(m_chgFuncp);
|
||||
// We need at least one change detect so we know to emit the correct code
|
||||
m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false));
|
||||
//
|
||||
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?");
|
||||
m_statep->m_scopetopp = scopep;
|
||||
|
||||
// Create a wrapper change detection function that calls each change detection function
|
||||
m_statep->m_tlChgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "QData");
|
||||
m_statep->m_tlChgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
m_statep->m_tlChgFuncp->symProlog(true);
|
||||
m_statep->m_tlChgFuncp->declPrivate(true);
|
||||
m_statep->m_scopetopp->addActivep(m_statep->m_tlChgFuncp);
|
||||
// Each change detection function needs at least one AstChangeDet
|
||||
// to ensure that V3EmitC outputs the necessary code.
|
||||
m_statep->maybeCreateChgFuncp();
|
||||
m_statep->m_chgFuncp->addStmtsp(new AstChangeDet(nodep->fileline(), NULL, NULL, false));
|
||||
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstVarScope* nodep, AstNUser*) {
|
||||
virtual void visit(AstVarScope* nodep) {
|
||||
if (nodep->isCircular()) {
|
||||
UINFO(8," CIRC "<<nodep<<endl);
|
||||
if (!nodep->user1()) {
|
||||
nodep->user1(true);
|
||||
if (!nodep->user1SetOnce()) {
|
||||
genChangeDet(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeMath* nodep) {
|
||||
// Short-circuit
|
||||
}
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ChangedVisitor(AstNetlist* nodep) {
|
||||
m_topModp = NULL;
|
||||
m_chgFuncp = NULL;
|
||||
m_scopetopp = NULL;
|
||||
ChangedVisitor(AstNetlist* nodep, ChangedState* statep) {
|
||||
m_statep = statep;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~ChangedVisitor() {}
|
||||
@@ -156,5 +300,7 @@ public:
|
||||
|
||||
void V3Changed::changedAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ChangedVisitor visitor (nodep);
|
||||
ChangedState state;
|
||||
ChangedVisitor visitor (nodep, &state);
|
||||
V3Global::dumpCheckGlobalTree("changed", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Pre C-Emit stage changes
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+65
-43
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Add temporaries, such as for clean nodes
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -24,7 +23,7 @@
|
||||
// For each math operator, if it requires a clean operand,
|
||||
// and the operand is dirty, insert a CLEAN node.
|
||||
// Resize operands to C++ 32/64/wide types.
|
||||
// Copy all width() values to minWidth() so RANGE, etc can still see orig widths
|
||||
// Copy all width() values to widthMin() so RANGE, etc can still see orig widths
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
@@ -47,15 +46,17 @@ private:
|
||||
// NODE STATE
|
||||
// Entire netlist:
|
||||
// AstNode::user() -> CleanState. For this node, 0==UNKNOWN
|
||||
// AstNode::user2() -> bool. True indicates minWidth has been propagated
|
||||
// AstNode::user2() -> bool. True indicates widthMin has been propagated
|
||||
// AstNodeDType::user3() -> AstNodeDType*. Alternative node with C size
|
||||
AstUser1InUse m_inuser1;
|
||||
AstUser2InUse m_inuser2;
|
||||
AstUser3InUse m_inuser3;
|
||||
|
||||
// TYPES
|
||||
enum CleanState { UNKNOWN, CLEAN, DIRTY };
|
||||
enum CleanState { CS_UNKNOWN, CS_CLEAN, CS_DIRTY };
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp;
|
||||
AstNodeModule* m_modp;
|
||||
|
||||
// METHODS
|
||||
static int debug() {
|
||||
@@ -70,16 +71,28 @@ private:
|
||||
else if (nodep->width()<=VL_QUADSIZE) return VL_QUADSIZE;
|
||||
else return nodep->widthWords()*VL_WORDSIZE;
|
||||
}
|
||||
void setCppWidth (AstNode* nodep, int width, int widthMin) {
|
||||
void setCppWidth (AstNode* nodep) {
|
||||
nodep->user2(true); // Don't resize it again
|
||||
nodep->width(width, widthMin);
|
||||
AstNodeDType* old_dtypep = nodep->dtypep();
|
||||
int width=cppWidth(nodep); // widthMin is unchanged
|
||||
if (old_dtypep->width() != width) {
|
||||
// Since any given dtype's cppWidth() is the same, we can just
|
||||
// remember one convertion for each, and reuse it
|
||||
if (AstNodeDType* new_dtypep = old_dtypep->user3p()->castNodeDType()) {
|
||||
nodep->dtypep(new_dtypep);
|
||||
} else {
|
||||
nodep->dtypeChgWidth(width, nodep->widthMin());
|
||||
AstNodeDType* new_dtypep2 = nodep->dtypep();
|
||||
if (new_dtypep2 == old_dtypep) nodep->v3fatalSrc("Dtype didn't change when width changed");
|
||||
old_dtypep->user3p(new_dtypep2); // Remember for next time
|
||||
}
|
||||
}
|
||||
}
|
||||
void computeCppWidth (AstNode* nodep) {
|
||||
if (!nodep->user2()) {
|
||||
if (nodep->castVar()) { // Don't want to change variable widths!
|
||||
setCppWidth(nodep, nodep->width(), nodep->width()); // set widthMin anyways so can see it later
|
||||
if (!nodep->user2() && nodep->hasDType()) {
|
||||
if (nodep->castVar() || nodep->castNodeDType()) { // Don't want to change variable widths!
|
||||
} else {
|
||||
setCppWidth(nodep, cppWidth(nodep), nodep->widthMin());
|
||||
setCppWidth(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -93,15 +106,15 @@ private:
|
||||
}
|
||||
bool isClean(AstNode* nodep) {
|
||||
CleanState clstate = getCleanState(nodep);
|
||||
if (clstate==CLEAN) return true;
|
||||
if (clstate==DIRTY) return false;
|
||||
nodep->v3fatalSrc("Unknown clean state on node.");
|
||||
if (clstate==CS_CLEAN) return true;
|
||||
if (clstate==CS_DIRTY) return false;
|
||||
nodep->v3fatalSrc("Unknown clean state on node: "+nodep->prettyTypeName());
|
||||
return false;
|
||||
}
|
||||
void setClean(AstNode* nodep, bool isClean) {
|
||||
computeCppWidth (nodep); // Just to be sure it's in widthMin
|
||||
bool wholeUint = ((nodep->widthMin() % VL_WORDSIZE) == 0); //32,64,...
|
||||
setCleanState(nodep, ((isClean||wholeUint) ? CLEAN:DIRTY));
|
||||
setCleanState(nodep, ((isClean||wholeUint) ? CS_CLEAN:CS_DIRTY));
|
||||
}
|
||||
|
||||
// Operate on nodes
|
||||
@@ -116,7 +129,7 @@ private:
|
||||
AstNode* cleanp = new AstAnd (nodep->fileline(),
|
||||
new AstConst (nodep->fileline(), mask),
|
||||
nodep);
|
||||
setCppWidth (cleanp, cppWidth(nodep), nodep->widthMin());
|
||||
cleanp->dtypeFrom(nodep); // Otherwise the AND normally picks LHS
|
||||
relinkHandle.relink(cleanp);
|
||||
}
|
||||
void insureClean(AstNode* nodep) {
|
||||
@@ -160,12 +173,12 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
m_modp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeUniop* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeUniop* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanLhs()) {
|
||||
@@ -173,45 +186,45 @@ private:
|
||||
}
|
||||
setClean (nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeBiop* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeBiop* nodep) {
|
||||
operandBiop(nodep);
|
||||
setClean (nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstAnd* nodep, AstNUser*) {
|
||||
virtual void visit(AstAnd* nodep) {
|
||||
operandBiop(nodep);
|
||||
setClean (nodep, isClean(nodep->lhsp()) || isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstXor* nodep, AstNUser*) {
|
||||
virtual void visit(AstXor* nodep) {
|
||||
operandBiop(nodep);
|
||||
setClean (nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstOr* nodep, AstNUser*) {
|
||||
virtual void visit(AstOr* nodep) {
|
||||
operandBiop(nodep);
|
||||
setClean (nodep, isClean(nodep->lhsp()) && isClean(nodep->rhsp()));
|
||||
}
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeMath* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
computeCppWidth(nodep);
|
||||
setClean (nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
computeCppWidth(nodep);
|
||||
if (nodep->cleanRhs()) {
|
||||
insureClean(nodep->rhsp());
|
||||
}
|
||||
}
|
||||
virtual void visit(AstText* nodep, AstNUser*) {
|
||||
virtual void visit(AstText* nodep) {
|
||||
setClean (nodep, true);
|
||||
}
|
||||
virtual void visit(AstScopeName* nodep, AstNUser*) {
|
||||
virtual void visit(AstScopeName* nodep) {
|
||||
setClean (nodep, true);
|
||||
}
|
||||
virtual void visit(AstSel* nodep, AstNUser*) {
|
||||
virtual void visit(AstSel* nodep) {
|
||||
operandTriop(nodep);
|
||||
setClean (nodep, nodep->cleanOut());
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep, AstNUser*) {
|
||||
virtual void visit(AstUCFunc* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
computeCppWidth(nodep);
|
||||
setClean (nodep, false);
|
||||
@@ -221,52 +234,61 @@ private:
|
||||
}
|
||||
insureCleanAndNext (nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstTraceInc* nodep, AstNUser*) {
|
||||
virtual void visit(AstTraceInc* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureCleanAndNext (nodep->valuep());
|
||||
}
|
||||
virtual void visit(AstTypedef* nodep) {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstParamTypeDType* nodep) {
|
||||
// No cleaning, or would loose pointer to enum
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
// Control flow operators
|
||||
virtual void visit(AstNodeCond* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeCond* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureClean(nodep->condp());
|
||||
setClean(nodep, isClean(nodep->expr1p()) && isClean(nodep->expr2p()));
|
||||
}
|
||||
virtual void visit(AstWhile* nodep, AstNUser*) {
|
||||
virtual void visit(AstWhile* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureClean(nodep->condp());
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureClean(nodep->condp());
|
||||
}
|
||||
virtual void visit(AstNodePli* nodep, AstNUser*) {
|
||||
virtual void visit(AstSFormatF* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureCleanAndNext (nodep->exprsp());
|
||||
setClean(nodep, true); // generates a string, so not relevant
|
||||
}
|
||||
virtual void visit(AstUCStmt* nodep, AstNUser*) {
|
||||
virtual void visit(AstUCStmt* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureCleanAndNext (nodep->bodysp());
|
||||
}
|
||||
virtual void visit(AstCCall* nodep, AstNUser*) {
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
insureCleanAndNext (nodep->argsp());
|
||||
setClean (nodep, true);
|
||||
}
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
computeCppWidth(nodep);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CleanVisitor() {}
|
||||
virtual ~CleanVisitor() {}
|
||||
void main(AstNetlist* nodep) {
|
||||
explicit CleanVisitor(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~CleanVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
@@ -274,6 +296,6 @@ public:
|
||||
|
||||
void V3Clean::cleanAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CleanVisitor visitor;
|
||||
visitor.main(nodep);
|
||||
CleanVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("clean", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Pre C-Emit stage changes
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+43
-42
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into sensitivity active domains
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2008-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2008-2017 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.
|
||||
@@ -68,7 +66,7 @@ class GaterVarVertex;
|
||||
class GaterVertex : public V3GraphVertex {
|
||||
static uint32_t s_rankNum;
|
||||
public:
|
||||
GaterVertex(V3Graph* graphp)
|
||||
explicit GaterVertex(V3Graph* graphp)
|
||||
: V3GraphVertex(graphp) {
|
||||
s_rankNum++; rank(s_rankNum);
|
||||
}
|
||||
@@ -81,7 +79,7 @@ uint32_t GaterVertex::s_rankNum = 0;
|
||||
|
||||
class GaterHeadVertex : public GaterVertex {
|
||||
public:
|
||||
GaterHeadVertex(V3Graph* graphp)
|
||||
explicit GaterHeadVertex(V3Graph* graphp)
|
||||
: GaterVertex(graphp) {}
|
||||
virtual ~GaterHeadVertex() {}
|
||||
virtual int typeNum() const { return __LINE__; } // C++ typeof() equivelent
|
||||
@@ -91,7 +89,7 @@ public:
|
||||
|
||||
class GaterPliVertex : public GaterVertex {
|
||||
public:
|
||||
GaterPliVertex(V3Graph* graphp)
|
||||
explicit GaterPliVertex(V3Graph* graphp)
|
||||
: GaterVertex(graphp) {}
|
||||
virtual ~GaterPliVertex() {}
|
||||
virtual int typeNum() const { return __LINE__; } // C++ typeof() equivelent
|
||||
@@ -201,25 +199,25 @@ private:
|
||||
if (m_isSimple) nodep->iterateChildren(*this);
|
||||
}
|
||||
// VISITORS
|
||||
virtual void visit(AstOr* nodep, AstNUser*) { okIterate(nodep); }
|
||||
virtual void visit(AstAnd* nodep, AstNUser*) { okIterate(nodep); }
|
||||
virtual void visit(AstNot* nodep, AstNUser*) { okIterate(nodep); }
|
||||
virtual void visit(AstLogOr* nodep, AstNUser*) { okIterate(nodep); }
|
||||
virtual void visit(AstLogAnd* nodep, AstNUser*) { okIterate(nodep); }
|
||||
virtual void visit(AstLogNot* nodep, AstNUser*) { okIterate(nodep); }
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) { okIterate(nodep); }
|
||||
virtual void visit(AstOr* nodep) { okIterate(nodep); }
|
||||
virtual void visit(AstAnd* nodep) { okIterate(nodep); }
|
||||
virtual void visit(AstNot* nodep) { okIterate(nodep); }
|
||||
virtual void visit(AstLogOr* nodep) { okIterate(nodep); }
|
||||
virtual void visit(AstLogAnd* nodep) { okIterate(nodep); }
|
||||
virtual void visit(AstLogNot* nodep) { okIterate(nodep); }
|
||||
virtual void visit(AstVarRef* nodep) { okIterate(nodep); }
|
||||
|
||||
// Other possibilities are equals, etc
|
||||
// But, we don't want to get too complicated or it will take too much
|
||||
// effort to calculate the gater
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
m_isSimple = false;
|
||||
//nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
GaterCondVisitor(AstNode* nodep) {
|
||||
explicit GaterCondVisitor(AstNode* nodep) {
|
||||
m_isSimple = true;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
@@ -250,10 +248,10 @@ class GaterBodyVisitor : public GaterBaseVisitor {
|
||||
uint32_t m_state; // Parsing state
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
if (nodep->lvalue()) {
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
if (vscp->user2p()->castNode() == m_exprp) {
|
||||
if (vscp->user2p() == m_exprp) {
|
||||
// This variable's block needs to move to the new always
|
||||
if (m_original) {
|
||||
UINFO(9," VARREF delete in old: "<<nodep<<endl);
|
||||
@@ -274,11 +272,11 @@ class GaterBodyVisitor : public GaterBaseVisitor {
|
||||
}
|
||||
}
|
||||
|
||||
//virtual void visit(AstNodeIf* nodep, AstNUser*) { ... }
|
||||
//virtual void visit(AstNodeIf* nodep) { ... }
|
||||
// Not needed, it's the same handling as any other statement. Cool, huh?
|
||||
// (We may get empty IFs but the constant propagater will rip them up for us)
|
||||
|
||||
virtual void visit(AstNodeStmt* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeStmt* nodep) {
|
||||
uint32_t oldstate = m_state;
|
||||
// Find if children want to delete this or not.
|
||||
// Note children may bicker, and want to both keep and delete (branches on a if)
|
||||
@@ -298,7 +296,7 @@ class GaterBodyVisitor : public GaterBaseVisitor {
|
||||
}
|
||||
|
||||
if ((childstate & STATE_DELETE) && !(childstate & STATE_KEEP)) {
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
// Pass upwards we did delete
|
||||
m_state |= STATE_DELETE;
|
||||
} else {
|
||||
@@ -306,7 +304,7 @@ class GaterBodyVisitor : public GaterBaseVisitor {
|
||||
m_state |= STATE_KEEP;
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
@@ -315,6 +313,7 @@ public:
|
||||
m_exprp = exprp;
|
||||
m_original = original;
|
||||
m_state = STATE_UNKNOWN;
|
||||
m_cloning = false;
|
||||
if (debug()>=9) nodep->dumpTree(cout," GateBodyIn: ");
|
||||
nodep->bodysp()->iterateAndNext(*this);
|
||||
if (debug()>=9) nodep->dumpTree(cout," GateBodyOut: ");
|
||||
@@ -428,7 +427,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
for (V3GraphEdge* nextp,* edgep = m_pliVertexp->outBeginp(); edgep; edgep = nextp) {
|
||||
nextp = edgep->outNextp(); // We may edit the list
|
||||
if (GaterVarVertex* vVxp = dynamic_cast<GaterVarVertex*>(edgep->top())) {
|
||||
vVxp->unlinkDelete(&m_graph); vVxp=NULL; edgep=NULL;
|
||||
vVxp->unlinkDelete(&m_graph); VL_DANGLING(vVxp); VL_DANGLING(edgep);
|
||||
} else {
|
||||
m_graph.dump();
|
||||
v3fatalSrc("PLI vertex points to non-signal");
|
||||
@@ -464,7 +463,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
V3GraphVertex* toVxp = edgep->top();
|
||||
//UINFO(9," to "<<toVxp->user()<<" "<<toVxp<<endl);
|
||||
if ((toVxp->user() & VU_IF) && (toVxp->user() & VU_ELSE)) {
|
||||
edgep->unlinkDelete(); edgep = NULL;
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
if (!(toVxp->user() & VU_MADE)) { // Make an edge only once
|
||||
toVxp->user(toVxp->user() | VU_MADE);
|
||||
GaterEdge* inedgep = static_cast<GaterEdge*>(vertexp->inBeginp());
|
||||
@@ -488,7 +487,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
if (toVxp->user() && toVxp->user() < depth) {
|
||||
// A recursion "above" us marked it,
|
||||
// Remove this edge, it's redundant with the upper edge
|
||||
edgep->unlinkDelete(); edgep=NULL;
|
||||
edgep->unlinkDelete(); VL_DANGLING(edgep);
|
||||
} else {
|
||||
GaterEdge* cedgep = static_cast<GaterEdge*>(edgep);
|
||||
if (cedgep->ifelseBoth()) {
|
||||
@@ -516,7 +515,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
if (GaterIfVertex* toVxp = dynamic_cast<GaterIfVertex*>(edgep->top())) {
|
||||
if (!toVxp->outBeginp()) {
|
||||
if (!nextp || nextp->top() != edgep->top()) { // Else next would disappear; we'll do it next loop
|
||||
toVxp->unlinkDelete(&m_graph); toVxp=NULL; edgep=NULL;
|
||||
toVxp->unlinkDelete(&m_graph); VL_DANGLING(toVxp); VL_DANGLING(edgep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -530,7 +529,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
nextp = edgep->outNextp(); // We may edit the list
|
||||
if (GaterVarVertex* toVxp = dynamic_cast<GaterVarVertex*>(edgep->top())) {
|
||||
if (!nextp || nextp->top() != edgep->top()) { // Else next would disappear; we'll do it next loop
|
||||
toVxp->unlinkDelete(&m_graph); toVxp=NULL; edgep=NULL;
|
||||
toVxp->unlinkDelete(&m_graph); VL_DANGLING(toVxp); VL_DANGLING(edgep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -560,7 +559,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
if (!vVxp->inBeginp()) {
|
||||
// At this point, any variable not linked is an error
|
||||
// (It should have at least landed under the Head node)
|
||||
vVxp->nodep()->v3fatalSrc("Variable became stranded in clk gate detection\n");
|
||||
vVxp->nodep()->v3fatalSrc("Variable became stranded in clk gate detection");
|
||||
}
|
||||
if (!lastVxp || vVxp->sortCmp(lastVxp)) {
|
||||
// Different sources for this new node
|
||||
@@ -612,7 +611,8 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
// Edges from IFs represent a real IF branch in the equation tree
|
||||
//UINFO(9," ifver "<<(void*)(edgep)<<" cc"<<edgep->dotColor()<<endl);
|
||||
eqnp = cVxp->nodep()->condp()->cloneTree(true);
|
||||
if (eqnp && cedgep->ifelseFalse()) {
|
||||
if (!eqnp) cVxp->nodep()->v3fatalSrc("null condition");
|
||||
if (cedgep->ifelseFalse()) {
|
||||
eqnp = new AstNot(eqnp->fileline(),eqnp);
|
||||
}
|
||||
// We need to AND this term onto whatever was found below it
|
||||
@@ -685,6 +685,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
AstNode* bodyp = nodep->bodysp()->cloneTree(true);
|
||||
|
||||
AstAlways* alwp = new AstAlways(nodep->fileline(),
|
||||
nodep->keyword(),
|
||||
sensesp,
|
||||
bodyp);
|
||||
|
||||
@@ -696,16 +697,15 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
// Blow old statements from new body
|
||||
GaterBodyVisitor(alwp,exprp,false);
|
||||
|
||||
m_statGaters++;
|
||||
++m_statGaters;
|
||||
if (debug()>=9) alwp->dumpTree(cout," new: ");
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
if (debug()>=9) cout<<endl<<endl<<endl;
|
||||
UINFO(5, "Gater: ALWAYS: "<<nodep<<endl);
|
||||
if (nodep->user4()) return;
|
||||
nodep->user4(1);
|
||||
if (nodep->user4SetOnce()) return;
|
||||
|
||||
clear();
|
||||
|
||||
@@ -752,7 +752,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
}
|
||||
UINFO(5, " Gater done"<<endl);
|
||||
}
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
virtual void visit(AstVarRef* nodep) {
|
||||
if (nodep->lvalue()) {
|
||||
AstVarScope* vscp = nodep->varScopep();
|
||||
if (nodep->varp()->isSigPublic()) {
|
||||
@@ -779,7 +779,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeIf* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeIf* nodep) {
|
||||
m_ifDepth++;
|
||||
bool allowGater = m_directlyUnderAlw && m_ifDepth <= IF_DEPTH_MAX;
|
||||
if (allowGater) {
|
||||
@@ -820,12 +820,12 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
m_ifDepth--;
|
||||
}
|
||||
|
||||
virtual void visit(AstAssignDly* nodep, AstNUser*) {
|
||||
virtual void visit(AstAssignDly* nodep) {
|
||||
// iterateChildrenAlw will detect this is a statement for us
|
||||
iterateChildrenAlw(nodep, false);
|
||||
}
|
||||
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeAssign* nodep) {
|
||||
// Note NOT AssignDly; handled above, We'll just mark this block as
|
||||
// not optimizable.
|
||||
//
|
||||
@@ -837,7 +837,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
// No reason to iterate.
|
||||
}
|
||||
|
||||
virtual void visit(AstSenItem* nodep, AstNUser*) {
|
||||
virtual void visit(AstSenItem* nodep) {
|
||||
if (!nodep->isClocked()) {
|
||||
nonOptimizable(nodep, "Non-clocked sensitivity");
|
||||
}
|
||||
@@ -845,7 +845,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
}
|
||||
|
||||
//--------------------
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
if (m_nonopt=="") { // Else accelerate
|
||||
iterateChildrenAlw(nodep, false);
|
||||
}
|
||||
@@ -862,9 +862,9 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
m_stmtVscp = NULL;
|
||||
m_stmtInPli = false;
|
||||
}
|
||||
if (!nodep->isSplittable()) {
|
||||
if (!nodep->isPure() || nodep->isBrancher()) {
|
||||
// May also be a new statement (above if); if so we mark it immediately
|
||||
UINFO(9," NotSplittable "<<nodep<<endl);
|
||||
UINFO(9," NotPure "<<nodep<<endl);
|
||||
scoreboardPli(nodep);
|
||||
}
|
||||
{
|
||||
@@ -879,7 +879,7 @@ class GaterVisitor : public GaterBaseVisitor {
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
GaterVisitor(AstNode* nodep) {
|
||||
explicit GaterVisitor(AstNetlist* nodep) {
|
||||
// AstAlways visitor does the real work, so most zeroing needs to be in clear()
|
||||
clear();
|
||||
nodep->accept(*this);
|
||||
@@ -915,4 +915,5 @@ void V3ClkGater::clkGaterAll(AstNetlist* nodep) {
|
||||
// While the gater does well at some modules, it seems to slow down many others
|
||||
UINFO(5,"ClkGater is disabled due to performance issues\n");
|
||||
//GaterVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("clkgater", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into clock gated blocks
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+57
-198
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Clocking POS/NEGEDGE insertion
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -60,7 +59,7 @@ private:
|
||||
enum { DOUBLE_OR_RATE = 10 }; // How many | per ||, Determined experimentally as best
|
||||
|
||||
// STATE
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstTopScope* m_topScopep; // Current top scope
|
||||
AstScope* m_scopep; // Current scope
|
||||
AstActive* m_activep; // Current block
|
||||
@@ -83,11 +82,9 @@ private:
|
||||
AstVarScope* getCreateLastClk(AstVarScope* vscp) {
|
||||
if (vscp->user1p()) return ((AstVarScope*)vscp->user1p());
|
||||
AstVar* varp = vscp->varp();
|
||||
if (varp->width()!=1) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
|
||||
string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName());
|
||||
AstVar* newvarp
|
||||
= new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, NULL, NULL); // No range; 1 bit.
|
||||
newvarp->width(1,1);
|
||||
if (!varp->width1()) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
|
||||
string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->name());
|
||||
AstVar* newvarp = new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, VFlagLogicPacked(), 1);
|
||||
m_modp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
|
||||
vscp->user1p(newvscp);
|
||||
@@ -102,18 +99,6 @@ private:
|
||||
UINFO(4,"New Last: "<<newvscp<<endl);
|
||||
return newvscp;
|
||||
}
|
||||
AstVarScope* getCreateLocalVar(FileLine* fl, const string& name, AstVar* examplep, int width) {
|
||||
AstVar* newvarp;
|
||||
if (width) {
|
||||
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, new AstRange(fl, width-1, 0));
|
||||
} else {
|
||||
newvarp = new AstVar (fl, AstVarType::BLOCKTEMP, name, examplep); // No range; 1 bit.
|
||||
}
|
||||
m_modp->addStmtp(newvarp);
|
||||
AstVarScope* newvscp = new AstVarScope(fl, m_scopep, newvarp);
|
||||
m_scopep->addVarp(newvscp);
|
||||
return newvscp;
|
||||
}
|
||||
AstNode* createSenItemEquation(AstSenItem* nodep) {
|
||||
// We know the var is clean, and one bit, so we use binary ops
|
||||
// for speed instead of logical ops.
|
||||
@@ -123,8 +108,14 @@ private:
|
||||
// HIGHEDGE: var
|
||||
// LOWEDGE: ~var
|
||||
AstNode* newp = NULL;
|
||||
if (nodep->edgeType()==AstEdgeType::ET_ILLEGAL) {
|
||||
if (!v3Global.opt.bboxUnsup()) {
|
||||
nodep->v3error("Unsupported: Complicated event expression in sensitive activity list");
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
AstVarScope* clkvscp = nodep->varrefp()->varScopep();
|
||||
if (nodep->edgeType()==AstEdgeType::POSEDGE) {
|
||||
if (nodep->edgeType()==AstEdgeType::ET_POSEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
@@ -132,23 +123,23 @@ private:
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
lastVscp, false)));
|
||||
} else if (nodep->edgeType()==AstEdgeType::NEGEDGE) {
|
||||
} else if (nodep->edgeType()==AstEdgeType::ET_NEGEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstAnd(nodep->fileline(),
|
||||
new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
nodep->varrefp()->varScopep(), false)),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
} else if (nodep->edgeType()==AstEdgeType::BOTHEDGE) {
|
||||
} else if (nodep->edgeType()==AstEdgeType::ET_BOTHEDGE) {
|
||||
AstVarScope* lastVscp = getCreateLastClk(clkvscp);
|
||||
newp = new AstXor(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
nodep->varrefp()->varScopep(), false),
|
||||
new AstVarRef(nodep->fileline(), lastVscp, false));
|
||||
} else if (nodep->edgeType()==AstEdgeType::HIGHEDGE) {
|
||||
} else if (nodep->edgeType()==AstEdgeType::ET_HIGHEDGE) {
|
||||
newp = new AstVarRef(nodep->fileline(),
|
||||
clkvscp, false);
|
||||
} else if (nodep->edgeType()==AstEdgeType::LOWEDGE) {
|
||||
} else if (nodep->edgeType()==AstEdgeType::ET_LOWEDGE) {
|
||||
newp = new AstNot(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(),
|
||||
clkvscp, false));
|
||||
@@ -197,11 +188,11 @@ private:
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstTopScope* nodep, AstNUser*) {
|
||||
virtual void visit(AstTopScope* nodep) {
|
||||
UINFO(4," TOPSCOPE "<<nodep<<endl);
|
||||
m_topScopep=nodep;
|
||||
m_scopep = nodep->scopep();
|
||||
if (!m_scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n");
|
||||
if (!m_scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?");
|
||||
//VV***** We reset all user1p()
|
||||
AstNode::user1ClearTree();
|
||||
// Make top functions
|
||||
@@ -233,10 +224,9 @@ private:
|
||||
funcp->slow(true);
|
||||
funcp->isStatic(false);
|
||||
funcp->entryPoint(true);
|
||||
funcp->addInitsp(
|
||||
new AstCStmt(nodep->fileline(),
|
||||
" "+EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline()," "+EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline(),
|
||||
EmitCBaseVisitor::symClassVar()+" = this->__VlSymsp;\n"));
|
||||
funcp->addInitsp(new AstCStmt(nodep->fileline(), EmitCBaseVisitor::symTopAssign()+"\n"));
|
||||
m_scopep->addActivep(funcp);
|
||||
m_finalFuncp = funcp;
|
||||
}
|
||||
@@ -259,14 +249,14 @@ private:
|
||||
m_topScopep=NULL;
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
//UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_stableNum = 0;
|
||||
nodep->iterateChildren(*this);
|
||||
m_modp= NULL;
|
||||
}
|
||||
virtual void visit(AstScope* nodep, AstNUser*) {
|
||||
virtual void visit(AstScope* nodep) {
|
||||
//UINFO(4," SCOPE "<<nodep<<endl);
|
||||
m_scopep = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
@@ -277,27 +267,25 @@ private:
|
||||
}
|
||||
m_scopep = NULL;
|
||||
}
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
virtual void visit(AstAlways* nodep) {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
|
||||
nodep->replaceWith(cmtp);
|
||||
AstNode* stmtsp = nodep->bodysp();
|
||||
if (stmtsp) {
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
cmtp->addNextHere(stmtsp);
|
||||
}
|
||||
nodep->deleteTree(); nodep = NULL;
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
virtual void visit(AstAlwaysPost* nodep, AstNUser*) {
|
||||
virtual void visit(AstAlwaysPost* nodep) {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
|
||||
nodep->replaceWith(cmtp);
|
||||
AstNode* stmtsp = nodep->bodysp();
|
||||
if (stmtsp) {
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
cmtp->addNextHere(stmtsp);
|
||||
}
|
||||
nodep->deleteTree(); nodep = NULL;
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
|
||||
virtual void visit(AstCoverToggle* nodep) {
|
||||
//nodep->dumpTree(cout,"ct:");
|
||||
//COVERTOGGLE(INC, ORIG, CHANGE) ->
|
||||
// IF(ORIG ^ CHANGE) { INC; CHANGE = ORIG; }
|
||||
@@ -315,55 +303,28 @@ private:
|
||||
newp->addIfsp(new AstAssign(nodep->fileline(),
|
||||
changep->cloneTree(false),
|
||||
origp->cloneTree(false)));
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
|
||||
nodep->replaceWith(newp); nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
virtual void visit(AstInitial* nodep, AstNUser*) {
|
||||
virtual void visit(AstInitial* nodep) {
|
||||
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
|
||||
nodep->replaceWith(cmtp);
|
||||
AstNode* stmtsp = nodep->bodysp();
|
||||
if (stmtsp) {
|
||||
if (AstNode* stmtsp = nodep->bodysp()) {
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
cmtp->addNextHere(stmtsp);
|
||||
}
|
||||
nodep->deleteTree(); nodep = NULL;
|
||||
nodep->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
void moveInitial(AstActive* nodep) {
|
||||
// Change to CFunc
|
||||
AstNode* stmtsp = nodep->stmtsp();
|
||||
if (stmtsp) {
|
||||
if (!m_scopep) nodep->v3fatalSrc("Initial Active not under scope\n");
|
||||
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_initial__"+m_scopep->nameDotless(),
|
||||
m_scopep);
|
||||
funcp->argTypes(EmitCBaseVisitor::symClassVar());
|
||||
funcp->symProlog(true);
|
||||
funcp->slow(true);
|
||||
stmtsp->unlinkFrBackWithNext();
|
||||
funcp->addStmtsp(stmtsp);
|
||||
nodep->replaceWith(funcp);
|
||||
// Add top level call to it
|
||||
AstCCall* callp = new AstCCall(nodep->fileline(), funcp);
|
||||
callp->argTypes("vlSymsp");
|
||||
m_initFuncp->addStmtsp(callp);
|
||||
} else {
|
||||
nodep->unlinkFrBack();
|
||||
}
|
||||
nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
// Link to global function
|
||||
if (nodep->formCallTree()) {
|
||||
if (nodep->name() == "_final") {
|
||||
UINFO(4, " formCallTree "<<nodep<<endl);
|
||||
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
|
||||
callp->argTypes("vlSymsp");
|
||||
m_finalFuncp->addStmtsp(callp);
|
||||
} else {
|
||||
nodep->v3fatalSrc("Unknown CFunc name. Make code more generic, with a map of func names");
|
||||
}
|
||||
UINFO(4, " formCallTree "<<nodep<<endl);
|
||||
AstCCall* callp = new AstCCall(nodep->fileline(), nodep);
|
||||
callp->argTypes("vlSymsp");
|
||||
m_finalFuncp->addStmtsp(callp);
|
||||
}
|
||||
}
|
||||
virtual void visit(AstSenTree* nodep, AstNUser*) {
|
||||
virtual void visit(AstSenTree* nodep) {
|
||||
// Delete it later; Actives still pointing to it
|
||||
nodep->unlinkFrBack();
|
||||
pushDeletep(nodep);
|
||||
@@ -376,22 +337,24 @@ private:
|
||||
if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body
|
||||
else m_settleFuncp->addStmtsp(stmtsp); // else add to top level function
|
||||
}
|
||||
virtual void visit(AstActive* nodep, AstNUser*) {
|
||||
void addToInitial(AstNode* stmtsp) {
|
||||
if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body
|
||||
else m_initFuncp->addStmtsp(stmtsp); // else add to top level function
|
||||
}
|
||||
virtual void visit(AstActive* nodep) {
|
||||
// Careful if adding variables here, ACTIVES can be under other ACTIVES
|
||||
// Need to save and restore any member state in AstUntilStable block
|
||||
if (nodep->hasInitial()) {
|
||||
moveInitial(nodep);
|
||||
}
|
||||
else if (!m_topScopep || !nodep->stmtsp()) {
|
||||
if (!m_topScopep || !nodep->stmtsp()) {
|
||||
// Not at the top or empty block...
|
||||
// Only empty blocks should be leftover on the non-top. Killem.
|
||||
if (nodep->stmtsp()) nodep->v3fatalSrc("Non-empty lower active");
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
} else {
|
||||
UINFO(4," ACTIVE "<<nodep<<endl);
|
||||
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
|
||||
if (nodep->hasClocked()) {
|
||||
// Remember the latest sensitivity so we can compare it next time
|
||||
if (nodep->hasInitial()) nodep->v3fatalSrc("Initial block should not have clock sensitivity");
|
||||
if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
|
||||
UINFO(4," sameSenseTree\n");
|
||||
} else {
|
||||
@@ -403,6 +366,10 @@ private:
|
||||
}
|
||||
// Move statements to if
|
||||
m_lastIfp->addIfsp(stmtsp);
|
||||
} else if (nodep->hasInitial()) {
|
||||
// Don't need to: clearLastSen();, as we're adding it to different cfunc
|
||||
// Move statements to function
|
||||
addToInitial(stmtsp);
|
||||
} else if (nodep->hasSettle()) {
|
||||
// Don't need to: clearLastSen();, as we're adding it to different cfunc
|
||||
// Move statements to function
|
||||
@@ -413,128 +380,19 @@ private:
|
||||
// Move statements to function
|
||||
addToEvalLoop(stmtsp);
|
||||
}
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
|
||||
nodep->unlinkFrBack()->deleteTree(); VL_DANGLING(nodep);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef NEW_ORDERING
|
||||
virtual void visit(AstUntilStable* nodep, AstNUser*) {
|
||||
// Process any sub ACTIVE statements first
|
||||
UINFO(4," UNTILSTABLE "<<nodep<<endl);
|
||||
{
|
||||
// Keep vars if in middle of other stable
|
||||
AstUntilStable* lastUntilp = m_untilp;
|
||||
AstSenTree* lastSenp = m_lastSenp;
|
||||
AstIf* lastIfp = m_lastIfp;
|
||||
m_untilp = nodep;
|
||||
m_lastSenp = NULL;
|
||||
m_lastIfp = NULL;
|
||||
nodep->iterateChildren(*this);
|
||||
m_untilp = lastUntilp;
|
||||
m_lastSenp = lastSenp;
|
||||
m_lastIfp = lastIfp;
|
||||
}
|
||||
// Set "unstable" to 100. (non-stabilization count)
|
||||
// int __VclockLoop = 0
|
||||
// IData __Vchange = 1
|
||||
// while (__Vchange) {
|
||||
// Save old values of each until stable variable
|
||||
// Evaluate the body
|
||||
// __Vchange = {change_detect} contribution
|
||||
// if (++__VclockLoop > 100) converge_error
|
||||
if (debug()>4) nodep->dumpTree(cout, " UntilSt-old: ");
|
||||
FileLine* fl = nodep->fileline();
|
||||
if (nodep->bodysp()) fl = nodep->bodysp()->fileline(); // Point to applicable code...
|
||||
m_stableNum++;
|
||||
AstNode* origBodysp = nodep->bodysp(); if (origBodysp) origBodysp->unlinkFrBackWithNext();
|
||||
AstVarScope* changeVarp = getCreateLocalVar(fl, "__Vchange"+cvtToStr(m_stableNum), NULL, 32);
|
||||
AstVarScope* countVarp = getCreateLocalVar(fl, "__VloopCount"+cvtToStr(m_stableNum), NULL, 32);
|
||||
AstWhile* untilp = new AstWhile(fl, new AstVarRef(fl, changeVarp, false), NULL);
|
||||
AstNode* preUntilp = new AstComment(fl, "Change loop "+cvtToStr(m_stableNum));
|
||||
preUntilp->addNext(new AstAssign(fl, new AstVarRef(fl, changeVarp, true),
|
||||
new AstConst(fl, 1)));
|
||||
preUntilp->addNext(new AstAssign(fl, new AstVarRef(fl, countVarp, true),
|
||||
new AstConst(fl, 0)));
|
||||
|
||||
// Add stable variables & preinits
|
||||
AstNode* setChglastp = NULL;
|
||||
for (AstVarRef* varrefp = nodep->stablesp(); varrefp; varrefp=varrefp->nextp()->castVarRef()) {
|
||||
AstVarScope* cmpvscp = getCreateLocalVar(varrefp->varp()->fileline(),
|
||||
"__Vchglast"+cvtToStr(m_stableNum)+"__"+varrefp->name(),
|
||||
varrefp->varp(), 0);
|
||||
varrefp->varScopep()->user2p(cmpvscp);
|
||||
setChglastp = setChglastp->addNext(
|
||||
new AstAssign(fl, new AstVarRef(fl, cmpvscp, true),
|
||||
new AstVarRef(fl, varrefp->varScopep(), false)));
|
||||
}
|
||||
if (!setChglastp) nodep->v3fatalSrc("UntilStable without any variables");
|
||||
untilp->addBodysp(setChglastp);
|
||||
untilp->addBodysp(new AstComment(fl, "Change Loop body begin"));
|
||||
if (origBodysp) untilp->addBodysp(origBodysp);
|
||||
untilp->addBodysp(new AstComment(fl, "Change Loop body end"));
|
||||
// Add stable checks
|
||||
// The order of the variables doesn't matter, but it's more expensive to test
|
||||
// wide variables, and more so 64 bit wide ones. Someday it might be faster to
|
||||
// set the changed variable in a "distributed" fashion over the code, IE,
|
||||
// logic... logic.... a=....; Changed |= (a ^ old_a); more logic... Changed |=...
|
||||
// But then, one hopes users don't have much unoptimized logic
|
||||
AstNode* changeExprp = NULL;
|
||||
int doublecount = 0;
|
||||
for (int wide=0; wide<3; wide++) { // Adding backwards; wide, quad, then normal
|
||||
for (AstVarRef* varrefp = nodep->stablesp(); varrefp; varrefp=varrefp->nextp()->castVarRef()) {
|
||||
if (wide== ( varrefp->isQuad()?0:(varrefp->isWide() ? 1:2))) {
|
||||
AstVarScope* cmpvscp = (AstVarScope*)(varrefp->varScopep()->user2p());
|
||||
if (!cmpvscp) varrefp->v3fatalSrc("should have created above");
|
||||
AstChangeXor* changep
|
||||
= new AstChangeXor (fl,
|
||||
new AstVarRef(fl, varrefp->varScopep(), false),
|
||||
new AstVarRef(fl, cmpvscp, false));
|
||||
if (!changeExprp) changeExprp = changep;
|
||||
else if (doublecount++ > DOUBLE_OR_RATE) {
|
||||
doublecount = 0;
|
||||
changeExprp = new AstLogOr (fl, changep, changeExprp);
|
||||
} else {
|
||||
changeExprp = new AstOr (fl, changep, changeExprp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!changeExprp) nodep->v3fatalSrc("UntilStable without any variables");
|
||||
changeExprp = new AstAssign(fl, new AstVarRef(fl, changeVarp, true),
|
||||
changeExprp);
|
||||
untilp->addBodysp(changeExprp);
|
||||
//
|
||||
// Final body
|
||||
AstNode* ifstmtp = new AstAssign(fl, new AstVarRef(fl, countVarp, true),
|
||||
new AstAdd(fl, new AstConst(fl, 1),
|
||||
new AstVarRef(fl, countVarp, false)));
|
||||
ifstmtp->addNext(new AstIf(fl,
|
||||
new AstLt (fl, new AstConst(fl, 100),
|
||||
new AstVarRef(fl, countVarp, false)),
|
||||
(new AstDisplay (fl, AstDisplayType::DISPLAY,
|
||||
"%%Error: Verilated model didn't converge", NULL, NULL))
|
||||
->addNext(new AstStop (fl)),
|
||||
NULL));
|
||||
untilp->addBodysp(new AstIf(fl, new AstNeq(fl, new AstConst(fl, 0),
|
||||
new AstVarRef(fl, changeVarp, false)),
|
||||
ifstmtp, NULL));
|
||||
//
|
||||
// Replace it
|
||||
preUntilp->addNext(untilp);
|
||||
if (debug()>4) preUntilp->dumpTreeAndNext(cout, " UntilSt-new: ");
|
||||
nodep->replaceWith(preUntilp); nodep->deleteTree(); nodep=NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ClockVisitor(AstNode* nodep) {
|
||||
explicit ClockVisitor(AstNetlist* nodep) {
|
||||
m_modp=NULL; m_activep=NULL;
|
||||
m_evalFuncp = NULL;
|
||||
m_topScopep=NULL;
|
||||
@@ -555,4 +413,5 @@ public:
|
||||
void V3Clock::clockAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
ClockVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("clock", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Clocking POS/NEGEDGE insertion
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
+37
-31
@@ -1,13 +1,12 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Combine common code into functions
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
@@ -70,8 +69,12 @@ protected:
|
||||
virtual ~CombBaseVisitor() {}
|
||||
|
||||
//***** optimization levels
|
||||
bool emptyFunctionDeletion() { return true; }
|
||||
bool duplicateFunctionCombine() { return true; }
|
||||
static bool emptyFunctionDeletion() { return true; }
|
||||
static bool duplicateFunctionCombine() { return true; }
|
||||
// Note this is disabled, it still needed work
|
||||
// Also repair it for DPI functions; when make __common need to insure proper
|
||||
// flags get inherited from the old to new AstCFunc, and that AstText doesn't
|
||||
// get split between functions causing the text to have a danginling reference.
|
||||
bool statementCombine() { return false && duplicateFunctionCombine(); }
|
||||
};
|
||||
|
||||
@@ -101,14 +104,14 @@ public:
|
||||
if (callp->funcp() != oldfuncp) callp->v3fatalSrc("Call list broken, points to call w/different func");
|
||||
if (newfuncp) {
|
||||
AstCCall* newp = new AstCCall(callp, newfuncp);
|
||||
newp->argTypes(callp->argTypes());
|
||||
// Special new AstCCall form above transfers children of callp to newfuncp
|
||||
callp->replaceWith(newp);
|
||||
addCall(newp); // Fix the table
|
||||
} else { // Just deleting empty function
|
||||
callp->unlinkFrBack();
|
||||
}
|
||||
callp->user3(true); // Dead now
|
||||
pushDeletep(callp); callp=NULL;
|
||||
pushDeletep(callp); VL_DANGLING(callp);
|
||||
m_callMmap.erase(eqit); // Fix the table
|
||||
}
|
||||
}
|
||||
@@ -131,18 +134,20 @@ public:
|
||||
}
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstCCall* nodep, AstNUser*) {
|
||||
virtual void visit(AstCCall* nodep) {
|
||||
addCall(nodep);
|
||||
}
|
||||
// Speed things up
|
||||
virtual void visit(AstNodeAssign* nodep, AstNUser*) {}
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeAssign* nodep) {}
|
||||
virtual void visit(AstNodeMath* nodep) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CombCallVisitor() {}
|
||||
CombCallVisitor() {
|
||||
m_find = false;
|
||||
}
|
||||
virtual ~CombCallVisitor() {}
|
||||
void main(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
@@ -158,13 +163,13 @@ private:
|
||||
// OUTPUT:
|
||||
// AstNode::user3() -> bool. True to indicate duplicated
|
||||
// VISITORS
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->user3(true);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
CombMarkVisitor(AstNode* nodep) {
|
||||
explicit CombMarkVisitor(AstNode* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~CombMarkVisitor() {}
|
||||
@@ -189,7 +194,7 @@ private:
|
||||
typedef enum {STATE_IDLE, STATE_HASH, STATE_DUP} CombineState;
|
||||
V3Double0 m_statCombs; // Statistic tracking
|
||||
CombineState m_state; // Major state
|
||||
AstModule* m_modp; // Current module
|
||||
AstNodeModule* m_modp; // Current module
|
||||
AstCFunc* m_funcp; // Current function
|
||||
V3Hash m_lowerHash; // Hash of the statement we're building
|
||||
CombCallVisitor m_call; // Tracking of function call users
|
||||
@@ -225,7 +230,7 @@ private:
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
m_call.replaceFunc(oldfuncp, NULL);
|
||||
oldfuncp->unlinkFrBack();
|
||||
pushDeletep(oldfuncp); oldfuncp=NULL;
|
||||
pushDeletep(oldfuncp); VL_DANGLING(oldfuncp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -234,7 +239,7 @@ private:
|
||||
V3Hash hashval = it->first;
|
||||
AstNode* node1p = it->second;
|
||||
if (!node1p->castCFunc()) continue;
|
||||
if (hashval.isIllegal()) node1p->v3fatalSrc("Illegal (unhashed) nodes\n");
|
||||
if (hashval.isIllegal()) node1p->v3fatalSrc("Illegal (unhashed) nodes");
|
||||
for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) {
|
||||
AstNode* node2p = eqit->second;
|
||||
if (!(eqit->first == hashval)) break;
|
||||
@@ -253,11 +258,11 @@ private:
|
||||
UINFO(5," DupFunc "<<hex<<V3Hash(newfuncp->user4p())<<" "<<newfuncp<<endl);
|
||||
UINFO(5," and "<<hex<<V3Hash(oldfuncp->user4p())<<" "<<oldfuncp<<endl);
|
||||
// Mark user3p on entire old tree, so we don't process it more
|
||||
m_statCombs++;
|
||||
++m_statCombs;
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
m_call.replaceFunc(oldfuncp, newfuncp);
|
||||
oldfuncp->unlinkFrBack();
|
||||
pushDeletep(oldfuncp); oldfuncp=NULL;
|
||||
pushDeletep(oldfuncp); VL_DANGLING(oldfuncp);
|
||||
}
|
||||
void replaceOnlyCallFunc(AstCCall* nodep) {
|
||||
if (AstCFunc* oldfuncp = nodep->backp()->castCFunc()) {
|
||||
@@ -269,7 +274,7 @@ private:
|
||||
UINFO(9," Function only has call "<<oldfuncp<<endl);
|
||||
m_call.deleteCall(nodep);
|
||||
CombMarkVisitor visitor(oldfuncp);
|
||||
replaceFuncWFunc(oldfuncp, nodep->funcp()); nodep=NULL;
|
||||
replaceFuncWFunc(oldfuncp, nodep->funcp()); VL_DANGLING(nodep);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -379,12 +384,12 @@ private:
|
||||
m_call.addCall(call2p);
|
||||
// If either new statement makes a func with only a single call, replace
|
||||
// the above callers to call it directly
|
||||
replaceOnlyCallFunc(call1p); call1p=NULL;
|
||||
replaceOnlyCallFunc(call2p); call2p=NULL;
|
||||
replaceOnlyCallFunc(call1p); VL_DANGLING(call1p);
|
||||
replaceOnlyCallFunc(call2p); VL_DANGLING(call2p);
|
||||
}
|
||||
|
||||
// VISITORS
|
||||
virtual void visit(AstNetlist* nodep, AstNUser*) {
|
||||
virtual void visit(AstNetlist* nodep) {
|
||||
// Track all callers of each function
|
||||
m_call.main(nodep);
|
||||
//
|
||||
@@ -393,7 +398,7 @@ private:
|
||||
// Required so that a module instantiating another can benefit from collapsing.
|
||||
nodep->iterateChildrenBackwards(*this);
|
||||
}
|
||||
virtual void visit(AstModule* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeModule* nodep) {
|
||||
UINFO(4," MOD "<<nodep<<endl);
|
||||
m_modp = nodep;
|
||||
m_modNFuncs = 0;
|
||||
@@ -421,7 +426,7 @@ private:
|
||||
}
|
||||
m_modp = NULL;
|
||||
}
|
||||
virtual void visit(AstCFunc* nodep, AstNUser*) {
|
||||
virtual void visit(AstCFunc* nodep) {
|
||||
m_funcp = nodep;
|
||||
if (!nodep->dontCombine()) {
|
||||
if (m_state == STATE_HASH) {
|
||||
@@ -432,7 +437,7 @@ private:
|
||||
}
|
||||
m_funcp = NULL;
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep, AstNUser*) {
|
||||
virtual void visit(AstNodeStmt* nodep) {
|
||||
if (m_state == STATE_HASH && m_funcp) {
|
||||
hashStatement(nodep);
|
||||
}
|
||||
@@ -443,16 +448,16 @@ private:
|
||||
|
||||
//--------------------
|
||||
// Default: Just iterate
|
||||
virtual void visit(AstVar*, AstNUser*) {}
|
||||
virtual void visit(AstTraceDecl*, AstNUser*) {}
|
||||
virtual void visit(AstTraceInc*, AstNUser*) {}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
virtual void visit(AstVar*) {}
|
||||
virtual void visit(AstTraceDecl*) {}
|
||||
virtual void visit(AstTraceInc*) {}
|
||||
virtual void visit(AstNode* nodep) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
CombineVisitor(AstNetlist* nodep) {
|
||||
explicit CombineVisitor(AstNetlist* nodep) {
|
||||
m_modp=NULL;
|
||||
m_funcp = NULL;
|
||||
m_state = STATE_IDLE;
|
||||
@@ -469,4 +474,5 @@ public:
|
||||
void V3Combine::combineAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
CombineVisitor visitor (nodep);
|
||||
V3Global::dumpCheckGlobalTree("combine", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3);
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,14 +1,12 @@
|
||||
// -*- C++ -*-
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Combine common code into functions
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
|
||||
// Copyright 2003-2017 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.
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Configuration Files
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2010-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3String.h"
|
||||
#include "V3Config.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class V3ConfigLine {
|
||||
public:
|
||||
int m_lineno; // Line number to make change at
|
||||
V3ErrorCode m_code; // Error code
|
||||
bool m_on; // True to enaable message
|
||||
V3ConfigLine(V3ErrorCode code, int lineno, bool on)
|
||||
: m_lineno(lineno), m_code(code), m_on(on) {}
|
||||
~V3ConfigLine() {}
|
||||
inline bool operator< (const V3ConfigLine& rh) const {
|
||||
if (m_lineno<rh.m_lineno) return true;
|
||||
if (m_lineno>rh.m_lineno) return false;
|
||||
if (m_code<rh.m_code) return true;
|
||||
if (m_code>rh.m_code) return false;
|
||||
// Always turn "on" before "off" so that overlapping lines will end up finally with the error "off"
|
||||
return (m_on>rh.m_on);
|
||||
}
|
||||
};
|
||||
ostream& operator<<(ostream& os, V3ConfigLine rhs) { return os<<rhs.m_lineno<<", "<<rhs.m_code<<", "<<rhs.m_on; }
|
||||
|
||||
class V3ConfigIgnores {
|
||||
typedef multiset<V3ConfigLine> IgnLines; // list of {line,code,on}
|
||||
typedef map<string,IgnLines> IgnFiles; // {filename} => list of {line,code,on}
|
||||
|
||||
// MEMBERS
|
||||
string m_lastFilename; // Last filename looked up
|
||||
int m_lastLineno; // Last linenumber looked up
|
||||
|
||||
IgnLines::const_iterator m_lastIt; // Point with next linenumber > current line number
|
||||
IgnLines::const_iterator m_lastEnd; // Point with end()
|
||||
|
||||
IgnFiles m_ignWilds; // Ignores for each wildcarded filename
|
||||
IgnFiles m_ignFiles; // Ignores for each non-wildcarded filename
|
||||
|
||||
static V3ConfigIgnores s_singleton; // Singleton (not via local static, as that's slow)
|
||||
|
||||
V3ConfigIgnores() { m_lastLineno = -1; }
|
||||
~V3ConfigIgnores() {}
|
||||
|
||||
// METHODS
|
||||
inline IgnLines* findWilds(const string& wildname) {
|
||||
IgnFiles::iterator it = m_ignWilds.find(wildname);
|
||||
if (it != m_ignWilds.end()) {
|
||||
return &(it->second);
|
||||
} else {
|
||||
m_ignWilds.insert(make_pair(wildname, IgnLines()));
|
||||
it = m_ignWilds.find(wildname);
|
||||
return &(it->second);
|
||||
}
|
||||
}
|
||||
inline void absBuild(const string& filename) {
|
||||
// Given a filename, find all wildcard matches against it and build
|
||||
// hash with the specific filename. This avoids having to wildmatch
|
||||
// more than once against any filename.
|
||||
IgnFiles::iterator it = m_ignFiles.find(filename);
|
||||
if (it == m_ignFiles.end()) {
|
||||
// Haven't seen this filename before
|
||||
m_ignFiles.insert(make_pair(filename, IgnLines()));
|
||||
it = m_ignFiles.find(filename);
|
||||
// Make new list for this file of all matches
|
||||
for (IgnFiles::iterator fnit = m_ignWilds.begin(); fnit != m_ignWilds.end(); ++fnit) {
|
||||
if (VString::wildmatch(filename.c_str(), fnit->first.c_str())) {
|
||||
for (IgnLines::iterator lit = fnit->second.begin(); lit != fnit->second.end(); ++lit) {
|
||||
it->second.insert(*lit);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
m_lastIt = it->second.begin();
|
||||
m_lastEnd = it->second.end();
|
||||
}
|
||||
|
||||
public:
|
||||
inline static V3ConfigIgnores& singleton() { return s_singleton; }
|
||||
|
||||
void addIgnore(V3ErrorCode code, const string& wildname, int lineno, bool on) {
|
||||
// Insert
|
||||
IgnLines* linesp = findWilds(wildname);
|
||||
UINFO(9,"config addIgnore "<<wildname<<":"<<lineno<<", "<<code<<", "<<on<<endl);
|
||||
linesp->insert(V3ConfigLine(code, lineno, on));
|
||||
// Flush the match cache, due to a change in the rules.
|
||||
m_ignFiles.clear();
|
||||
m_lastFilename = " ";
|
||||
}
|
||||
inline void applyIgnores(FileLine* filelinep) {
|
||||
// HOT routine, called each parsed token line
|
||||
if (m_lastLineno != filelinep->lineno()
|
||||
|| m_lastFilename != filelinep->filename()) {
|
||||
//UINFO(9," ApplyIgnores for "<<filelinep->ascii()<<endl);
|
||||
if (VL_UNLIKELY(m_lastFilename != filelinep->filename())) {
|
||||
absBuild(filelinep->filename());
|
||||
m_lastFilename = filelinep->filename();
|
||||
}
|
||||
// Process all on/offs for lines up to and including the current line
|
||||
int curlineno = filelinep->lineno();
|
||||
for (; m_lastIt != m_lastEnd; ++m_lastIt) {
|
||||
if (m_lastIt->m_lineno > curlineno) break;
|
||||
//UINFO(9," Hit "<<*m_lastIt<<endl);
|
||||
filelinep->warnOn(m_lastIt->m_code, m_lastIt->m_on);
|
||||
}
|
||||
if (0 && debug() >= 9) {
|
||||
for (IgnLines::const_iterator it=m_lastIt; it != m_lastEnd; ++it) {
|
||||
UINFO(9," NXT "<<*it<<endl);
|
||||
}
|
||||
}
|
||||
m_lastLineno = filelinep->lineno();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
V3ConfigIgnores V3ConfigIgnores::s_singleton;
|
||||
|
||||
//######################################################################
|
||||
// V3Config
|
||||
|
||||
void V3Config::addIgnore(V3ErrorCode code, bool on, string filename, int min, int max) {
|
||||
if (filename=="*") {
|
||||
FileLine::globalWarnOff(code,!on);
|
||||
} else {
|
||||
V3ConfigIgnores::singleton().addIgnore(code, filename, min, on);
|
||||
if (max) V3ConfigIgnores::singleton().addIgnore(code, filename, max, !on);
|
||||
}
|
||||
}
|
||||
|
||||
void V3Config::applyIgnores(FileLine* filelinep) {
|
||||
V3ConfigIgnores::singleton().applyIgnores(filelinep);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Configuration Files
|
||||
//
|
||||
// Code available from: http://www.veripool.org/verilator
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2010-2017 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.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3CONFIG_H_
|
||||
#define _V3CONFIG_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <string>
|
||||
#include "V3Error.h"
|
||||
#include "V3FileLine.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class V3Config {
|
||||
public:
|
||||
static void addIgnore(V3ErrorCode code, bool on, string filename, int min, int max);
|
||||
static void applyIgnores(FileLine* filelinep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
+1189
-457
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user