File: internals.rst

package info (click to toggle)
verilator 5.044-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 69,096 kB
  • sloc: cpp: 152,937; python: 22,624; ansic: 11,002; yacc: 6,111; lex: 2,011; makefile: 1,428; sh: 603; perl: 302
file content (2654 lines) | stat: -rw-r--r-- 100,072 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
|Logo|

===================
Verilator Internals
===================

.. contents::
   :depth: 3

Introduction
============

This file discusses internal and programming details for Verilator. It's a
reference for developers and debugging problems.

See also the Verilator internals presentation at https://www.veripool.org.


Code Flows
==========


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 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.


Key Classes Used in the Verilator Flow
--------------------------------------


``AstNode``
~~~~~~~~~~~

The AST is represented at the top level by the class ``AstNode``. This
abstract class has derived classes for the individual components (e.g.
``AstGenerate`` for a generate block) or groups of components (e.g.
``AstNodeFTask`` for functions and tasks, which in turn has ``AstFunc`` and
``AstTask`` as derived classes). An important property of the ``AstNode``
type hierarchy is that all non-final subclasses of ``AstNode`` (i.e.: those
which themselves have subclasses) must be abstract as well, and be named
with the prefix ``AstNode*``. The ``astgen`` (see below) script relies on
this.

Each ``AstNode`` has pointers to up to four children, accessed by the
``op1p`` through ``op4p`` methods. These methods are then abstracted in a
specific Ast\* node class to a more specific name. For example, with the
``AstIf`` node (for ``if`` statements), ``thensp`` calls ``op2p`` to give
the pointer to the AST for the "then" block, while ``elsesp`` calls
``op3p`` to give the pointer to the AST for the "else" block, or NULL if
there is not one. These accessors are automatically generated by ``astgen``
after parsing the ``@astgen`` directives in the specific ``AstNode``
subclasses.

``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 ``back`` and ``next``
methods.

It is useful to remember that the derived class ``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 ``nodep`` as a
pointer to the ``AstNode`` currently being processed.

There are notable sub-hierarchies of the ``AstNode`` sub-types, namely:

1. All AST nodes representing data types derive from ``AstNodeDType``.

2. All AST nodes representing expressions (i.e.: anything that stands for,
   or evaluates to a value) derive from ``AstNodeExpr``.


``VNVisitor``
~~~~~~~~~~~~~

The passes are implemented by AST visitor classes. These are implemented by
subclasses of the abstract class, ``VNVisitor``. Each pass creates an
instance of the visitor class, which in turn implements a method to perform
the pass.


``V3Graph``
~~~~~~~~~~~

A number of passes use graph algorithms, and the class ``V3Graph`` is
provided to represent those graphs. Graphs are directed, and algorithms are
provided to manipulate the graphs and output them in `GraphViz
<https://www.graphviz.org>`__ dot format. ``V3Graph.h`` provides
documentation of this class.


``V3GraphVertex``
~~~~~~~~~~~~~~~~~

``V3GraphVertex`` is the base class for vertices in a graph. Vertices have
an associated ``fanout``, ``color`` and ``rank``, which may be used in
algorithms for ordering the graph. A generic ``user``/``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
``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()) {


``V3GraphEdge``
~~~~~~~~~~~~~~~

``V3GraphEdge`` is the base class for directed edges between pairs of
vertices. Edges have an associated ``weight`` and may also be made
``cutable``. A generic ``user``/``userp`` member variable is also provided.

Accessors, ``fromp`` and ``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
``V3GraphEdge``, which will reimplement these methods.


``V3GraphAlg``
~~~~~~~~~~~~~~

This is the base class for graph algorithms. It implements a ``bool``
method, ``followEdge`` which algorithms can use to decide whether an edge
is followed. This method returns true if the graph edge has a weight
greater than one and a user function, ``edgeFuncp`` (supplied in the
constructor) returns ``true``.

A number of predefined derived algorithm classes and access methods are
provided and documented in ``V3GraphAlg.cpp``.


``DfgGraph``
~~~~~~~~~~~~

The data-flow graph-based combinational logic optimizer (DFG optimizer)
converts an ``AstModule`` into a ``DfgGraph``. The graph represents the
combinational equations (~continuous assignments) in the module, and for
the duration of the DFG passes, it takes over the role of the represented
``AstModule``. The ``DfgGraph`` keeps hold of the represented
``AstModule``, and the ``AstModule`` retains all other logic that is not
representable as a data-flow graph. At the end of optimization, the
combinational logic represented by the ``DfgGraph`` is converted back into
AST form and is re-inserted into the corresponding ``AstModule``. The
``DfgGraph`` is distinct from ``V3Graph`` for efficiency and other
desirable properties which make writing DFG passes easier.


``DfgVertex``
~~~~~~~~~~~~~

The ``DfgGraph`` represents combinational logic equations as a graph of
``DfgVertex`` vertices. Each sub-class of ``DfgVertex`` corresponds to an
expression (a sub-class of ``AstNodeExpr``), a constant, or a variable
reference. LValues and RValues referencing the same storage location are
represented by the same ``DfgVertex``. Consumers of such vertices read as
the LValue, writers of such vertices write the RValue. The bulk of the
final ``DfgVertex`` sub-classes are generated by ``astgen`` from the
corresponding ``AstNode`` definitions.


Scheduling
----------

Verilator implements the Active and NBA regions of the SystemVerilog
scheduling model as described in IEEE 1800-2023 chapter 4, and in
particular sections 4.5 and Figure 4.1. The static (Verilation time)
scheduling of SystemVerilog processes is performed by code in the
``V3Sched`` namespace. The single entry point to the scheduling algorithm
is ``V3Sched::schedule``. Some preparatory transformations important for
scheduling are also performed in ``V3Active`` and ``V3ActiveTop``.
High-level evaluation functions are constructed by ``V3Order``, which
``V3Sched`` invokes on subsets of the logic in the design.

Scheduling deals with the problem of evaluating 'logic' in the correct
order and the correct number of times in order to compute the correct state
of the SystemVerilog program. Throughout this section, we use the term
'logic' to refer to all SystemVerilog constructs that describe the
evolution of the state of the program. In particular, all SystemVerilog
processes and continuous assignments are considered 'logic', but not for
example variable definitions without initialization or other miscellaneous
constructs.


Classes of logic
~~~~~~~~~~~~~~~~

The first step in the scheduling algorithm is to gather all the logic
present in the design, and classify it based on the conditions under which
the logic needs to be evaluated.

The classes of logic we distinguish between are:

- SystemVerilog ``initial`` processes, that need to be executed once at
  startup.

- Static variable initializers. These are a separate class as they need to
  be executed before ``initial`` processes.

- SystemVerilog ``final`` processes.

- Combinational logic. Any process or construct that has an implicit
  sensitivity list with no explicit sensitivities is considered
  'combinational' logic. This includes among other things, ``always @*``
  and ``always_comb`` processes, and continuous assignments. Verilator also
  converts some other ``always`` processes to combinational logic in
  ``V3Active`` as described below.

- Clocked logic. Any process or construct that has an explicit sensitivity
  list, with no implicit sensitivities, is considered 'clocked' (or
  'sequential') logic. This includes, among other things ``always`` and
  ``always_ff`` processes with an explicit sensitivity list.

Note that the distinction between clocked logic and combinational logic is
only important for the scheduling algorithm within Verilator as we handle
the two classes differently. It is possible to convert clocked logic into
combinational logic if the explicit sensitivity list of the clocked logic
is the same as the implicit sensitivity list of the equivalent
combinational logic would be. The canonical examples are: ``always @(a) x =
a;``, which is considered to be clocked logic by Verilator, and the
equivalent ``assign x = a;``, which is considered to be combinational
logic. ``V3Active`` in fact converts all clocked logic to combinational
logic whenever possible, as this provides advantages for scheduling as
described below.

There is also a 'hybrid' logic class, which has both explicit and implicit
sensitivities. This kind of logic does not arise from a SystemVerilog
construct, but is created during scheduling to break combinational cycles.
Details of this process and the hybrid logic class are described below.


Scheduling of simple classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SystemVerilog ``initial`` and ``final`` blocks can be scheduled (executed)
in an arbitrary order.

Static variable initializers need to be executed in source code order in
case there is a dependency between initializers, but the ordering of static
variable initialization is otherwise not defined by the SystemVerilog
standard (particularly, in the presence of hierarchical references in
static variable initializers).

The scheduling algorithm handles all three of these classes the same way
and schedules the logic in these classes in source code order. This step
yields the ``_eval_static``, ``_eval_initial`` and ``_eval_final``
functions which execute the corresponding logic constructs.


Scheduling of clocked and combinational logic
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

For performance, clocked and combinational logic needs to be ordered.
Conceptually this minimizes the iterations through the evaluation loop
presented in the reference algorithm in the SystemVerilog standard (IEEE
1800-2023 section 4.5), by evaluating logic constructs in data-flow order.
Without going into a lot of detail here, accept that well thought out
ordering is crucial to good simulation performance, and also enables
further optimizations later on.

At the highest level, ordering is performed by ``V3Order::order``, which is
invoked by ``V3Sched::schedule`` on various subsets of the combinational
and clocked logic as described below. The important thing to highlight now
is that ``V3Order::order`` operates by assuming that the state of all
variables driven by combinational logic is consistent with that
combinational logic. While this might seem subtle, it is very important, so
here is an example:

.. code-block:: sv

   always_comb d = q + 2;
   always @(posedge clock) q <= d;

During ordering, ``V3Order`` will assume that ``d`` equals ``q + 2`` at the
beginning of an evaluation step. As a result it will order the clocked
logic first, and all downstream combinational logic (like the assignment to
``d``) will execute after the clocked logic that drives inputs to the
combinational logic, in data-flow (or dependency) order. At the end of the
evaluation step, this ordering restores the invariant that variables driven
by combinational logic are consistent with that combinational logic (i.e.,
the circuit is in a settled/steady state).

One of the most important optimizations for performance is to only evaluate
combinational logic, if its inputs might have changed. For example, there
is no point in evaluating the above assignment to ``d`` on a negative edge
of the clock signal. Verilator does this by pushing the combinational logic
into the same (possibly multiple) event domains as the logic driving the
inputs to that combinational logic, and only evaluating the combinational
logic if at least one driving domain has been triggered. The impact of this
activity gating is very high (observed 100x slowdown on large designs when
turning it off), it is the reason we prefer to convert clocked logic to
combinational logic in ``V3Active`` whenever possible.

The ordering procedure described above works straightforward unless there
are combinational logic constructs that are circularly dependent (a.k.a.:
the UNOPTFLAT warning). Combinational scheduling loops can arise in sound
(realizable) circuits as Verilator considers each SystemVerilog process as
a unit of scheduling (albeit we do try to split processes into smaller ones
to avoid this circularity problem whenever possible, this is not always
possible).


Breaking combinational loops
~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Combinational loops are broken by the introduction of instances of the
'hybrid' logic class. As described in the previous section, combinational
loops require iteration until the logic is settled, in order to restore the
invariant that combinationally driven signals are consistent with the
combinational logic.

To achieve this, ``V3Sched::schedule`` calls ``V3Sched::breakCycles``,
which builds a dependency graph of all combinational logic in the design,
and then breaks all combinational cycles by converting all combinational
logic that consumes a variable driven via a 'back-edge' into hybrid logic.
Here 'back-edge' just means a graph edge that points from a higher-rank
vertex to a lower rank vertex in some consistent ranking of the directed
graph. Variables driven via a back-edge in the dependency graph are marked,
and all combinational logic that depends on such variables is converted
into hybrid logic, with the back-edge driven variables listed as explicit
'changed' sensitivities.

Hybrid logic is handled by ``V3Order`` mostly in the same way as
combinational logic, with two exceptions:

- Explicit sensitivities of hybrid logic are ignored for the purposes of
  data-flow ordering with respect to other combinational or hybrid logic.
  I.e.: an explicit sensitivity suppresses the implicit sensitivity on the
  same variable. This could also be interpreted as ordering the hybrid
  logic as if all variables listed as explicit sensitivities were
  substituted as constants with their current values.

- The explicit sensitivities are included as an additional driving domain
  of the logic, and also cause evaluation when triggered.

This means that hybrid logic is evaluated when either any of its implicit
sensitivities might have been updated (the same way as combinational logic,
by pushing it into the domains that write those variables), or if any of
its explicit sensitivities are triggered.

The effect of this transformation is that ``V3Order`` can proceed as if
there are no combinational cycles (or alternatively, under the assumption
that the back-edge-driven variables don't change during one evaluation
pass). The evaluation loop invoking the ordered code, will then re-invoke
it on a follow on iteration, if any of the explicit sensitivities of hybrid
logic have actually changed due to the previous invocation, iterating until
all the combinational (including hybrid) logic have settled.

One might wonder if there can be a race condition between clocked logic
triggered due to a combinational signal change from the previous evaluation
pass, and a combinational loop settling due to hybrid logic, if the clocked
logic reads the not yet settled combinationally driven signal. Such a race
is indeed possible, but our evaluation is consistent with the SystemVerilog
scheduling semantics (IEEE 1800-2023 chapter 4), and therefore any program
that exhibits such a race has non-deterministic behavior according to the
SystemVerilog semantics, so we accept this.


Settling combinational logic after initialization
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

At the beginning of simulation, once static initializer and ``initial``
blocks have been executed, we need to evaluate all combinational logic, in
order to restore the invariant utilized by ``V3Order`` that the state of
all combinationally driven variables are consistent with the combinational
logic.

To achieve this, we invoke ``V3Order::order`` on all of the combinational
and hybrid logic, and iterate the resulting evaluation function until no
more hybrid logic is triggered. This yields the `_eval_settle` function,
which is invoked at the beginning of simulation after the `_eval_initial`.


Partitioning logic for correct NBA updates
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``V3Order`` can order logic corresponding to non-blocking assignments
(NBAs) to yield correct simulation results, as long as all the sensitivity
expressions of clocked logic triggered in the Active scheduling region of
the current time step are known up front. I.e., the ordering of NBA updates
is only correct if derived clocks that are computed in an Active region
update (that is, via a blocking or continuous assignment) are known up
front.

We can ensure this by partitioning the logic into two regions. Note these
regions are a concept of the Verilator scheduling algorithm, and they do
not directly correspond to the similarly named SystemVerilog scheduling
regions as defined in the standard:

- All logic (clocked, combinational and hybrid) that transitively feeds
  into, or drives via a non-blocking or continuous assignments (or via any
  update that SystemVerilog executes in the Active scheduling region), a
  variable that is used in the explicit sensitivity list of some clocked or
  hybrid logic, is assigned to the 'act' region.

- All other logic is assigned to the 'nba' region.

For completeness, note that a subset of the 'act' region logic,
specifically, the logic related to the pre-assignments of NBA updates
(i.e., AstAlwaysPre nodes), is handled separately, but is executed as part
of the 'act' region.

Also note that all logic representing the committing of an NBA (i.e.,
Ast*Post) nodes) will be in the 'nba' region. This means that the
evaluation of the 'act' region logic will not commit any NBA updates. As a
result, the 'act' region logic can be iterated to compute all derived clock
signals up front.

The correspondence between the SystemVerilog Active and NBA scheduling
regions, and the internal 'act' and 'nba' regions, is that 'act' contains
all Active region logic that can compute a clock signal, while 'nba'
contains all other Active and NBA region logic. For example, if the only
clocks in the design are top-level inputs, then 'act' will be empty, and
'nba' will contain the whole of the design.

The partitioning described above is performed by ``V3Sched::partition``.


Replication of combinational logic
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

We will separately invoke ``V3Order::order`` on the 'act' and 'nba' region
logic.

Combinational logic that reads variables driven from both 'act' and 'nba'
region logic has the problem of needing to be reevaluated even if only one
of the regions updates an input variable. We could pass additional trigger
expressions between the regions to make sure combinational logic is always
reevaluated, or we can replicate combinational logic that is driven from
multiple regions, by copying it into each region that drives it.
Experiments show this simple replication works well performance-wise (and
notably ``V3Combine`` is good at combining the replicated code), so this is
what we do in ``V3Sched::replicateLogic``.

In ``V3Sched::replicateLogic``, in addition to replicating logic into the
'act' and 'nba' regions, we also replicate combinational (and hybrid) logic
that depends on top level inputs. These become a separate 'ico' region
(Input Combinational logic), which we will always evaluate at the beginning
of a time-step to ensure the combinational invariant holds even if input
signals have changed. Note that this eliminates the need of changing data
and clock signals on separate evaluations, as was necessary with earlier
versions of Verilator).


Constructing the top level `_eval` function
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

To construct the top level `_eval` function, which updates the state of the
circuit to the end of the current time step, we invoke ``V3Order::order``
separately on the 'ico', 'act' and 'nba' logic, which yields the
`_eval_ico`, `_eval_act`, and `_eval_nba` functions. We then put these all
together with the corresponding functions that compute the respective
trigger expressions into the top level `_eval` function, which on the high
level has the form:

.. code-block:: C++

   void _eval() {
      // Update combinational logic dependent on top level inputs ('ico' region)
      while (true) {
        _eval__triggers__ico();
        // If no 'ico' region trigger is active
        if (!ico_triggers.any()) break;
        _eval_ico();
      }

      // Iterate 'act' and 'nba' regions together
      while (true) {

        // Iterate 'act' region, this computes all derived clocks updaed in the
        // Active scheduling region, but does not commit any NBAs that executed
        // in 'act' region logic.
        while (true) {
          _eval__triggers__act();
          // If no 'act' region trigger is active
          if (!act_triggers.any()) break;
          // Remember what 'act' triggers were active, 'nba' uses the same
          latch_act_triggers_for_nba();
          _eval_act();
        }

        // If no 'nba' region trigger is active
        if (!nba_triggers.any()) break;

        // Evaluate all other Active region logic, and commit NBAs
        _eval_nba();
      }
   }


Timing
------

Timing support in Verilator utilizes C++ coroutines, which is a new feature
in C++20. The basic idea is to represent processes and tasks that await a
certain event or simulation time as coroutines. These coroutines get
suspended at the await, and resumed whenever the triggering event occurs,
or at the expected simulation time.

There are several runtime classes used for managing such coroutines defined
in ``verilated_timing.h`` and ``verilated_timing.cpp``.

``VlCoroutineHandle``
~~~~~~~~~~~~~~~~~~~~~

A thin wrapper around an ``std::coroutine_handle<>``. It forces move
semantics, destroys the coroutine if it remains suspended at the end of the
design's lifetime, and prevents multiple ``resume`` calls in the case of
``fork..join_any``.

``VlCoroutine``
~~~~~~~~~~~~~~~

Return value of all coroutines. Together with the promise type contained
within, it allows for chaining coroutines - resuming coroutines from up the
call stack. The calling coroutine's handle is saved in the promise object
as a continuation, that is, the coroutine that must be resumed after the
promise's coroutine finishes. This is necessary as C++ coroutines are
stackless, meaning each one is suspended independently of others in the
call graph.

``VlDelayScheduler``
~~~~~~~~~~~~~~~~~~~~

This class manages processes suspended by delays. There is one instance of
this class per design. Coroutines ``co_await`` this object's ``delay``
function. Internally, they are stored in a heap structure sorted by
simulation time in ascending order. When ``resume`` is called on the delay
scheduler, all coroutines awaiting the current simulation time are resumed.
The current simulation time is retrieved from a ``VerilatedContext``
object.

``VlTriggerScheduler``
~~~~~~~~~~~~~~~~~~~~~~

This class manages processes that await events (triggers). There is one
such object per each trigger awaited by coroutines. Coroutines ``co_await``
this object's ``trigger`` function. They are stored in two stages -
`uncommitted` and `ready`. First, they land in the `uncommitted` stage, and
cannot be resumed. The ``resume`` function resumes all coroutines from the
`ready` stage and moves `uncommitted` coroutines into `ready`. The
``commit`` function only moves `uncommitted` coroutines into `ready`.

This split is done to avoid self-triggering and triggering coroutines
multiple times. See the `Scheduling with timing` section for details on how
this is used.

``VlDynamicTriggerScheduler``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Like ``VlTriggerScheduler``, ``VlDynamicTriggerScheduler`` manages
processes that await triggers. However, it does not rely on triggers
evaluated externally by the 'act' trigger eval function. Instead, it is
also responsible for trigger evaluation. Coroutines that make use of this
scheduler must adhere to a certain procedure:

::

   __Vtrigger = 0;
   <locals and inits required for trigger eval>
   while (!__Vtrigger) {
       co_await __VdynSched.evaluation();
       <pre updates>;
       __Vtrigger = <trigger eval>;
       [optionally] co_await __VdynSched.postUpdate();
       <post updates>;
   }
   co_await __VdynSched.resumption();

The coroutines get resumed at trigger evaluation time, evaluate their local
triggers, optionally await the post update step, and if the trigger is set,
await proper resumption in the 'act' eval step.

``VlForkSync``
~~~~~~~~~~~~~~

Used for synchronizing ``fork..join`` and ``fork..join_any``. Forking
coroutines ``co_await`` its ``join`` function, and forked ones call
``done`` when they're finished. Once the required number of coroutines (set
using ``setCounter``) finish execution, the forking coroutine is resumed.

``VlForever``
~~~~~~~~~~~~~

A small utility awaitable type. It allows for blocking a coroutine forever.
It is currently only used for ``wait`` statements that await a constant
false condition. See the `Timing Pass` section for more details.

Timing Pass
~~~~~~~~~~~

There are two visitors in ``V3Timing.cpp``.

The first one, ``TimingSuspendableVisitor``, does not perform any AST
transformations. It is responsible for marking processes and C++ functions
that contain timing controls as suspendable. Processes that call
suspendable functions are also marked as suspendable. Functions that call,
are overridden by, or override suspendable functions are marked as
suspendable as well.

The visitor keeps a dependency graph of functions and processes to handle
such cases. A function or process is dependent on a function if it calls
it. A virtual class method is dependent on another class method if it calls
it, overrides it, or is overriden by it.

The second visitor in ``V3Timing.cpp``, ``TimingControlVisitor``, uses the
information provided by ``TimingSuspendableVisitor`` and transforms each
timing control into a ``co_await``.

* event controls are turned into ``co_await`` on a trigger scheduler's
  ``trigger`` method. The awaited trigger scheduler is the one
  corresponding to the sentree referenced by the event control. This
  sentree is also referenced by the ``AstCAwait`` node, to be used later by
  the static scheduling code.

* if an event control waits on a local variable or class member, it uses a
  local trigger which it evaluates inline. It awaits a dynamic trigger
  scheduler multiple times: for trigger evaluation, updates, and
  resumption. The dynamic trigger scheduler is responsible for resuming the
  coroutine at the correct point of evaluation.

* delays are turned into ``co_await`` on a delay scheduler's ``delay``
  method. The created ``AstCAwait`` nodes also reference a special sentree
  related to delays, to be used later by the static scheduling code.

* ``join`` and ``join_any`` are turned into ``co_await`` on a
  ``VlForkSync``'s ``join`` method. Each forked process gets a
  ``VlForkSync::done`` call at the end.

Assignments with intra-assignment timing controls are simplified into
assignments after those timing controls, with the LHS and RHS values
evaluated before them and stored in temporary variables.

``wait`` statements are transformed into while loops that check the
condition and then await changes in variables used in the condition. If the
condition is always false, the ``wait`` statement is replaced by a
``co_await`` on a ``VlForever``. This is done instead of a return in case
the ``wait`` is deep in a call stack (otherwise, the coroutine's caller
would continue execution).

Each sub-statement of a ``fork`` is put in an ``AstBegin`` node for easier
grouping. In a later step, each of these gets transformed into a new,
separate function. See the `Forks` section for more detail.

Suspendable functions get the return type of ``VlCoroutine``, which makes
them coroutines. Later, during ``V3Sched``, suspendable processes are also
transformed into coroutines.


Scheduling with timing
~~~~~~~~~~~~~~~~~~~~~~

Timing features in Verilator are built on top of the static scheduler.
Triggers are used for determining which delay or trigger schedulers should
resume. A special trigger is used for the delay scheduler. This trigger is
set if there are any coroutines awaiting the current simulation time
(``VlDelayScheduler::awaitingCurrentTime()``).

All triggers used by a suspendable process are mapped to variables written
in that process. When ordering code using ``V3Order``, these triggers are
provided as external domains of these variables. This ensures that the
necessary combinational logic is triggered after a coroutine resumption.

There are two functions for managing timing logic called by ``_eval()``:

* ``_timing_commit()``, which commits all coroutines whose triggers were
  not set in the current iteration,
* ``_timing_resume()``, which calls `resume()` on all trigger and delay
  schedulers whose triggers were set in the current iteration.

Thanks to this separation, a coroutine awaiting a trigger cannot be
suspended and resumed in the same iteration, and it cannot be resumed
before it suspends.

All coroutines are committed and resumed in the 'act' eval loop. With
timing features enabled, the ``_eval()`` function takes this form:

::

   void _eval() {
     while (true) {
       _eval__triggers__ico();
       if (!ico_triggers.any()) break;
       _eval_ico();
     }

     while (true) {
       while (true) {
         _eval__triggers__act();

         // Commit all non-triggered coroutines
         _timing_commit();

         if (!act_triggers.any()) break;
         latch_act_triggers_for_nba();

         // Resume all triggered coroutines
         _timing_resume();

         _eval_act();
       }
       if (!nba_triggers.any()) break;
       _eval_nba();
     }
   }

Forks
~~~~~

After the scheduling step, forks sub-statements are transformed into
separate functions, and these functions are called in place of the
sub-statements. These calls must be without ``co_await``, so that
suspension of a forked process doesn't suspend the forking process.

In forked processes, references to local variables are only allowed in
``fork..join``, as this is the only case that ensures the lifetime of these
locals are at least as long as the execution of the forked processes.


Multithreaded Mode
------------------

In ``--threads`` mode, the frontend of the Verilator pipeline is the same
as serial mode, up until V3Order.

``V3Order`` builds a fine-grained, statement-level dependency graph that
governs the ordering of code within a single ``eval()`` call. In serial
mode, that dependency graph is used to order all statements into a total
serial order. In parallel mode, the same dependency graph is the starting
point for a partitioner (``V3Partition``).

The partitioner's goal is to coarsen the fine-grained graph into a coarser
graph, while maintaining as much available parallelism as possible. Often
the partitioner can transform an input graph with millions of nodes into a
coarsened execution graph with a few dozen nodes, while maintaining enough
parallelism to take advantage of a modern multicore CPU. Runtime
synchronization cost is reasonable with so few nodes.


Partitioning
~~~~~~~~~~~~

Our partitioner is similar to the one Vivek Sarkar described in his 1989
paper *Partitioning and Scheduling Parallel Programs for Multiprocessors*.

Let's define some terms:


Par Factor
~~~~~~~~~~

The available parallelism or "par-factor" of a DAG is the total cost to
execute all nodes, divided by the cost to execute the longest critical path
through the graph. This is the speedup you would get from running the graph
in parallel, if given infinite CPU cores available and communication and
synchronization is zero.


Macro Task
~~~~~~~~~~

When the partitioner coarsens the graph, it combines nodes together. Each
fine-grained node represents an atomic "task"; combined nodes in the
coarsened graph are "macro-tasks". This term comes from Sarkar. Each
macro-task executes from start to end on one processor, without any
synchronization to any other macro-task during its execution.
(Synchronization only happens before the macro-task begins or after it
ends.)


Edge Contraction
~~~~~~~~~~~~~~~~

Verilator's partitioner, like Sarkar's, primarily relies on "edge
contraction" to coarsen the graph. It starts with one macro-task per atomic
task and iteratively combines pairs of edge-connected macro-tasks.


Local Critical Path
~~~~~~~~~~~~~~~~~~~

Each node in the graph has a "local" critical path. That's the critical
path from the start of the graph to the start of the node, plus the node's
cost, plus the critical path from the end of the node to the end of the
graph.

Sarkar calls out an important trade-off: coarsening the graph reduces
runtime synchronization overhead among the macro-tasks, but it tends to
increase the critical path through the graph and thus reduces par-factor.

Sarkar's partitioner, and ours, chooses pairs of macro-tasks to merge such
that the growth in critical path is minimized. Each candidate merge would
result in a new node, which would have some local critical path. We choose
the candidate that would produce the shortest local critical path. Repeat
until par-factor falls to a target threshold. It's a greedy algorithm, and
it's not guaranteed to produce the best partition (which Sarkar proves is
NP-hard).


Estimating Logic Costs
~~~~~~~~~~~~~~~~~~~~~~

To compute the cost of any given path through the graph, Verilator
estimates an execution cost for each task. Each macro-task has an execution
cost which is the sum of its tasks' costs. We assume that communication
overhead and synchronization overhead are zero, so the cost of any given
path through the graph is the sum of macro-task execution costs. Sarkar
does almost the same thing, except that he has nonzero estimates for
synchronization costs.

Verilator's cost estimates are assigned by ``InstrCountVisitor``. This
class is perhaps the most fragile piece of the multithread implementation.
It's easy to have a bug where you count something cheap (e.g. accessing one
element of a huge array) as if it were expensive (eg. by counting it as if
it were an access to the entire array.) Even without such gross bugs, the
estimates this produce are only loosely predictive of actual runtime cost.
Multithread performance would be better with better runtime costs
estimates. This is an area to improve.


Scheduling Macro-Tasks at Runtime
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After coarsening the graph, we must schedule the macro-tasks for runtime.
Sarkar describes two options: you can dynamically schedule tasks at
runtime, with a runtime graph follower. Sarkar calls this the
"macro-dataflow model." Verilator does not support this; early experiments
with this approach had poor performance.

The other option is to statically assign macro-tasks to threads, with each
thread running its macro-tasks in a static order. Sarkar describes this in
Chapter 5. Verilator takes this static approach. The only dynamic aspect is
that each macro task may block before starting, to wait until its
prerequisites on other threads have finished.

The synchronization cost is cheap if the prereqs are done. If they're not,
fragmentation (idle CPU cores waiting) is possible. This is the major
source of overhead in this approach. The ``--prof-exec`` switch and the
``verilator_gantt`` script can visualize the time lost to such
fragmentation.


Locating Variables for Best Spatial Locality
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

After scheduling all code, we attempt to locate variables in memory, such
that variables accessed by a single macro-task are close together in
memory. This provides "spatial locality" - when we pull in a 64-byte cache
line to access a 2-byte variable, we want the other 62 bytes to be ones
we'll also likely access soon, for best cache performance.

This is critical for performance. It should allow Verilator to scale to
very large models. We don't rely on our working set fitting in any CPU
cache; instead we essentially "stream" data into caches from memory. It's
not literally streaming, where the address increases monotonically, but it
should have similar performance characteristics, so long as each
macro-task's dataset fits in one core's local caches.

To achieve spatial locality, we tag each variable with the set of
macro-tasks that access it. Let's call this set the "footprint" of that
variable. The variables in a given module have a set of footprints. We can
order those footprints to minimize the distance between them (distance is
the number of macro-tasks that are different across any two footprints) and
then emit all variables into the struct in ordered-footprint order.

The footprint ordering is literally the traveling salesman problem, and we
use a TSP-approximation algorithm to get close to an optimal sort.

This is an old idea. Simulators designed at DEC in the early 1990s used
similar techniques to optimize both single-thread and multithread modes.
(Verilator does not optimize variable placement for spatial locality in
serial mode; that is a possible area for improvement.)


Improving Multithreaded Performance Further (a TODO list)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Wave Scheduling
+++++++++++++++

To allow the Verilated model to run in parallel with the testbench, it
might be nice to support "wave" scheduling, in which work on a cycle begins
before ``eval()`` is called or continues after ``eval()`` returns. For now,
all work on a cycle happens during the ``eval()`` call, leaving Verilator's
threads idle while the testbench (everything outside ``eval()``) is
working. This would involve fundamental changes within the partitioner,
however, it's probably the best bet for hiding testbench latency.


Efficient Dynamic Scheduling
++++++++++++++++++++++++++++

To scale to more than a few threads, we may revisit a fully dynamic
scheduler. For large (>16 core) systems, it might make sense to dedicate an
entire core to scheduling, so that scheduler data structures would fit in
its L1 cache and thus the cost of traversing priority-ordered ready lists
would not be prohibitive.


Static Scheduling with Runtime Repack
+++++++++++++++++++++++++++++++++++++

We could modify the static scheduling approach by gathering actual
macro-task execution times at run time, and dynamically re-packing the
macro-tasks into the threads also at run time. Say, re-pack once every
10,000 cycles or something. This has the potential to do better than our
static estimates about macro-task run times. It could potentially react to
CPU cores that aren't performing equally, due to NUMA or thermal throttling
or nonuniform competing memory traffic or whatever.


Clock Domain Balancing
++++++++++++++++++++++

Right now Verilator makes no attempt to balance clock domains across
macro-tasks. For a multi-domain model, that could lead to bad gantt chart
fragmentation. This could be improved if it's a real problem in practice.


Other Forms of MTask Balancing
++++++++++++++++++++++++++++++

The largest source of runtime overhead is idle CPUs, which happens due to
variance between our predicted runtime for each MTask and its actual
runtime. That variance is magnified if MTasks are homogeneous, containing
similar repeating logic which was generally close together in source code
and which is still packed together even after going through Verilator's
digestive tract.

If Verilator could avoid doing that, and instead would take source logic
that was close together and distribute it across MTasks, that would
increase the diversity of any given MTask, and this should reduce variance
in the cost estimates.

One way to do that might be to make various "tie breaker" comparison
routines in the sources to rely more heavily on randomness, and generally
try harder not to keep input nodes together when we have the option to
scramble things.

Profile-guided optimization make this a bit better, by adjusting mtask
scheduling, but this does not yet guide the packing into mtasks.


Performance Regression
++++++++++++++++++++++

It would be nice if we had a regression of large designs, with some
diversity of design styles, to test on both single- and multithreaded
modes. This would help to avoid performance regressions, and also to
evaluate the optimizations while minimizing the impact of parasitic noise.


Per-Instance Classes
++++++++++++++++++++

If we have multiple instances of the same module, and they partition
differently (likely; we make no attempt to partition them the same), then
the variable sort will be suboptimal for either instance. A possible
improvement would be to emit an unique class for each instance of a module,
and sort its variables optimally for that instance's code stream.


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.


Constrained randomization
-------------------------

Because general constrained randomization is a co-NP-hard problem, not all
cases are implemented in Verilator, and an external specialized SMT solver
is used for any non-obvious ones.

The ``randomize()`` method spawns an SMT solver in a sub-process. Then the
solver gets a setup query, then the definition of variables, then all the
constraints (SMT assertions) about the variables. Since the solver has no
information about the class' PRNG state, if the problem is satisfiable, the
solution space is further constrained by adding extra random constraints,
and querying the values satisfying the problem statement. The constraint is
currently constructed as fixing a simple xor of randomly chosen bits of the
variables being randomized.

The runtime classes used for handling the randomization are defined in
``verilated_random.h`` and ``verilated_random.cpp``.


``VlSubprocess``
~~~~~~~~~~~~~~~~

Subprocess handle, responsible for keeping track of the resources like
child PID, read and write file descriptors, and presenting them as a C++
iostream.


``VlRandomizer``
~~~~~~~~~~~~~~~~

Randomizer class, responsible for keeping track of variables and
constraints, and communicating with the solver subprocess.

The solver gets the constraints in `SMT-LIB2
<https://smtlib.cs.uiowa.edu/>`__ textual format in the following syntax:

::

   (set-info :smt-lib-version 2.0)
   (set-option :produce-models true)
   (set-logic QF_BV)

   (declare-fun v () (_ BitVec 16))
   (declare-fun w () (_ BitVec 64))
   (declare-fun x () (_ BitVec 48))
   (declare-fun z () (_ BitVec 24))
   (declare-fun t () (_ BitVec 23))
   (assert (or (= v #x0003) (= v #x0008)))
   (assert (= w #x0000000000000009))
   (assert (or (or (= x #x000000000001) (= x #x000000000002)) (or (= x #x000000000004) (= x #x000000000009))))
   (assert (bvult ((_ zero_extend 8) z) #x00000015))
   (assert (bvugt ((_ zero_extend 8) z) #x0000000d))

   (check-sat)

The solver responds with either ``sat`` or ``unsat``. Then the initial
solution is queried with:

::

   (get-value (v w x z t ))

The solver then responds with e.g.:

::

   ((v #x0008)
    (w #x0000000000000005)
    (x #x000000000002)
    (z #x000010)
    (t #b00000000000000000000000))

And then a follow-up query (or a series thereof) is asked, and the solver
gets reset, so that it can be reused by subsequent randomization attempts:

::

   (assert (= (bvxor (bvxor <...> (bvxor ((_ extract 21 21) z) ((_ extract 39 39) x)) ((_ extract 5 5) w)) <...> ((_ extract 10 10) w)) #b0))
   (check-sat)
   (get-value)
   ...
   (reset)


Coding Conventions
==================


Compiler Version and C++14
--------------------------

Verilator requires C14. Verilator does not require any newer versions, but
is maintained to build successfully with C17/C20.


Indentation and Naming Style
----------------------------

We will work with contributors to fix up indentation style issues, but it
is appreciated if you could match our style for C/C++:

- Use "mixedCapsSymbols" instead of "underlined_symbols".

- Use a "p" suffix on variables that are pointers, e.g., "nodep".

- Comment every member variable.

- In the include directory, use /// to document functions the user calls.
  (This convention has not been applied retroactively.)

C and Python indentation is automatically maintained with "make format"
using clang-format version 18, and yapf for Python, and is automatically
corrected in the CI actions. For those manually formatting C code:

- Use four spaces per level, and no tabs.

- Use two spaces between the end of source and the beginning of a comment.

- Use one space after if/for/switch/while and similar keywords.

- No spaces before semicolons, nor between a function's name and open
  parenthesis (only applies to functions; if/else has a following space).

Verilog indentation is not yet automatically maintained, but:

- Use two spaces per level, and no tabs.

- Place `begin` on the same line as the earlier starting statement e.g.
  `if`, and place the `end` on a separate line indented the same as the
  starting statement.


Commit messages
---------------

Pull requests do not typically edit ``Changes`` in order to reduce
potential merge conflicts. Instead, contributors should use an appropriate
first line of the git commit message. Maintainers periodically run
``nodist/log_changes`` which analyzes the commit messages to suggest edits
to the ``Changes`` file.

The format of a commit message should be typically of the forms below. The
github issue number, and github pull number if different should be
included.

"Add <some feature> (#1234)"
   For adding a new feature.

"Fix <some item> (#1234)"
   For a bug fix.

"Improve <some item> (#1234)"
   For improving something that previously existed.

"Optimize <some item> (#1234)"
   For improving performance.

"Support <some feature> (#1234)"
   For features that are described by IEEE were previously not supported.

"Commentary"
   For a super-trivial change to e.g. documentation. These will typically
   not get described in the Changes file.

"CI: <Add/Improve/etc as above> (#1234)"
   For changes that only concern github actions. These will typically not
   get described in the Changes file.

"Tests: <Add/Improve/etc as above> (#1234)"
   For changes that only concern tests. These will typically not get
   described in the Changes file.

"Internals: <Add/Improve/etc as above> (#1234)"
   For changes that only concern developers, e.g. code cleanups. These will
   typically not get described in the Changes file.

The line's grammar should match the phrasing used in the Changes file.

If the change does not affect user-visible function, also add "No
functional change." if it's 99% certain not to change behavior, or "No
functional change expected." if no change was expected but there may be
uncertainty.


The ``astgen`` Script
---------------------

The ``astgen`` script is used to generate some of the repetitive C++ code
related to the ``AstNode`` type hierarchy. An example is the abstract
``visit`` methods in ``VNVisitor``. There are other uses; please see the
``*__gen*`` files in the build directories and the ``astgen`` script for
details. A description of the more advanced features of ``astgen`` are
provided here.


Generating ``AstNode`` members
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Some of the member s of ``AstNode`` sub-classes are generated by
``astgen``. These are emitted as pre-processor macro definitions, which
then need to be added to the ``AstNode`` sub-classes they correspond to.
Specifically ``class AstFoo`` should contain an instance of
``ASTGEN_MEMBERS_AstFoo;`` at class scope. The ``astgen`` script checks and
errors if this is not present. The method generated depends on whether the
class is a concrete final class, or an abstract ``AstNode*`` base-class,
and on ``@astgen`` directives present in comment sections in the body of
the ``AstNode`` sub-class definitions.


List of ``@astgen`` directives
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

``@astgen`` directives in comments contained in the body of ``AstNode``
sub-class definitions are parsed and contribute to the code generated by
``astgen``. The general syntax is ``@astgen <keywords> := <description>``,
where ``<keywords>`` determines what is being defined, and
``<description>`` is a ``<keywords>`` dependent description of the
definition. The list of ``@astgen`` directives are as follows:


``op<N>`` operand directives
++++++++++++++++++++++++++++

The ``op1``, ``op2``, ``op3`` and ``op4`` directives are used to describe
the name and type of the up to 4 child operands of a node. The syntax of
the ``<description>`` field is ``<identifier> : <type>``, where
``<identifier>`` will be used as the base name of the generated operand
accessors, and ``<type>`` is one of:

1. An ``AstNode`` sub-class, defining the operand to be of that type,
   always no-null, and with an always null ``nextp()``. That is, the child
   node is always present, and is a single ``AstNode`` (as opposed to a
   list).

2. ``Optional[<AstNode sub-class>]``. This is just like in point 1 above,
   but defines the child node to be optional, meaning it may be null.

3. ``List[AstNode sub-class]`` describes a list operand, which means the
   child node may have a non-null ``nextp()`` and in addition the child
   itself may be null, representing an empty list.

An example of the full syntax of the directive is ``@astgen op1 := lhsp :
AstNodeExpr``.

``astnode`` generates accessors for the child nodes based on these
directives. For non-list children, the names of the getter and setter both
are that of the given ``<identifier>``. For list-type children, the getter
is ``<identifier>``, and instead of the setter, there an
``add<Identifier>`` method is generated that appends new nodes (or lists of
nodes) to the child list.


``alias op<N>`` operand alias directives
++++++++++++++++++++++++++++++++++++++++

If a super-class already defined a name and type for a child node using the
``op<N>`` directive, but a more appropriate name exists in the context of a
sub-class, then the alias directive can be used to introduce an additional
name for the child node. The is ``alias op<N> := <identifier>`` where
``<identifier>`` is the new name. ``op<N>`` must have been defined in some
super-class of the current node.

Example: ``@astgen alias op1 := condp``


Generating ``DfgVertex`` sub-classes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Most of the ``DfgVertex`` sub-classes are generated by ``astgen``, from the
definitions of the corresponding ``AstNode`` vertices.


Additional features of ``astgen``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

In addition to generating ``AstNode`` members as described above,
``astgen`` is also use to handle some of the repetitive implementation code
that is still variable enough not to be handled in C++ macros.

In particular, ``astgen`` is used to pre-process some of the C++ source
files. For example in ``V3Const.cpp``, it is used to implement the
``visit()`` functions for each binary operation using the ``TREEOP`` macro.

The original C++ source code is transformed into C++ code in the
``obj_opt`` and ``obj_dbg`` sub-directories (the former for the optimized
version of Verilator, the latter for the debug version). So for example
``V3Const.cpp`` into ``V3Const__gen.cpp``.


Visitor Functions
-----------------

Verilator uses the "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 https://en.wikipedia.org/wiki/Visitor_pattern.

As noted above, all visitors are derived classes of ``VNVisitor``. All
derived classes of ``AstNode`` implement the ``accept`` method, which takes
as argument a reference to an instance or a ``VNVisitor`` derived class and
applies the visit method of the ``VNVisitor`` to the invoking AstNode
instance (i.e. ``this``).

One possible difficulty is that a call to ``accept`` may perform an edit
which destroys the node it receives as an argument. The
``acceptSubtreeReturnEdits`` method of ``AstNode`` is provided to apply
``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
``visit`` function for the different ``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 ``accept`` on ``AstIf`` will look in turn for:

::

   void visit(AstIf* nodep)
   void visit(AstNodeIf* nodep)
   void visit(AstNodeStmt* nodep)
   void visit(AstNode* nodep)

There are 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 lose the upper for's
   setting.

2. User attributes. Each ``AstNode`` (**Note.** The AST node, not the
   visitor) has five user attributes, which may be accessed as an integer
   using the ``user1()`` through ``user4()`` methods, or as a pointer (of
   type ``AstNUser``) using the ``user1p()`` through ``user4p()`` methods
   (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
   ``VN_CAST(nodep->userp(), SOMETYPE)``. 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 `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 of
   type ``AstNUser`` that is ignored on most of the visitor functions.
   V3Width does this, but it proved messier 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.)


Iterators
---------

``VNVisitor`` provides a set of iterators to facilitate walking over the
tree. Each operates on the current ``VNVisitor`` class (as this) and takes
an argument type ``AstNode*``.

``iterate``
   Applies the ``accept`` method of the ``AstNode`` to the visitor
   function.

``iterateAndNextIgnoreEdit``
   Applies the ``accept`` method of each ``AstNode`` in a list (i.e.
   connected by ``nextp`` and ``backp`` pointers).

``iterateAndNextNull``
   Applies the ``accept`` method of each ``AstNode`` in a list, only if the
   provided node is non-NULL. If a node is edited by the call to
   ``accept``, apply ``accept`` again, until the node does not change.

``iterateListBackwards``
   Applies the ``accept`` method of each ``AstNode`` in a list, starting
   with the last one.

``iterateChildren``
   Applies the ``iterateAndNextNull`` method on each child ``op1p`` through
   ``op4p`` in turn.

``iterateChildrenBackwards``
   Applies the ``iterateListBackwards`` method on each child ``op1p``
   through ``op4p`` in turn.


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
   iterateAndNextNull(nodep->lhsp());  // and under covers nodep->lhsp() changes
   // nodep->lhsp() is 0x5678400
   iterateAndNextNull(nodep->lhsp());

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
   iterateAndNextNull(lp); **lhsp=NULL;**  // and under covers nodep->lhsp() changes
   // nodep->lhsp() is 0x5678400, lp is 0x1234000
   iterateAndNextNull(lp);

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 = acceptSubtreeReturnEdits(lp)


Identifying Derived Classes
---------------------------

A common requirement is to identify the specific ``AstNode`` class we are
dealing with. For example, a visitor might not implement separate ``visit``
methods for ``AstIf`` and ``AstGenIf``, but just a single method for the
base class:

::

   void visit(AstNodeIf* nodep)

However that method might want to specify additional code if it is called
for ``AstGenIf``. Verilator does this by providing a ``VN_IS`` method for
each possible node type, which returns true if the node is of that type (or
derived from that type). So our ``visit`` method could use:

::

   if (VN_IS(nodep, AstGenIf) {
     <code specific to AstGenIf>
   }

Additionally the ``VN_CAST`` method converts pointers similar to C++
``dynamic_cast``. This either returns a pointer to the object cast to that
type (if it is of class ``SOMETYPE``, or a derived class of ``SOMETYPE``)
or else NULL. (However, for true/false tests, use ``VN_IS`` as that is
faster.)


.. _testing:

Testing
=======

For an overview of how to write a test, see the BUGS section of the
`Verilator Manual <https://verilator.org/verilator_doc.html>`_.

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 ``_bad`` in their
name, and include ``fails = 1`` in either their ``compile`` or ``execute``
step as appropriate.


Preparing to Run Tests
----------------------

For all tests to pass, you must install the following packages:

- SystemC to compile the SystemC outputs, see https://systemc.org

- vcddiff to find differences in VCD outputs. See the readme at
  https://github.com/veripool/vcddiff

- Cmake for build paths that use it.


Controlling the Test Driver
---------------------------

The test driver script `driver.py` runs tests; see the `Test Driver`
section. The individual test drivers are written in Perl; see `Test
Language`.


Manual Test Execution
---------------------

A specific regression test can be executed manually. To start the "EXAMPLE"
test, run the following command.

::

   test_regress/t/t_EXAMPLE.py


Regression Testing for Developers
---------------------------------

Developers will also want to call ./configure with two extra flags:

``--enable-ccwarn``
   This 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.

``--enable-longtests``
   In addition to the standard C, SystemC examples, also run the tests in
   the ``test_regress`` directory when using *make test*'. This is disabled
   by default, as SystemC installation problems would otherwise falsely
   indicate a Verilator problem.

There are some traps to avoid when running regression tests

- When checking the MANIFEST, the test will fail on unexpected code in the
  Verilator tree. So make sure to keep any such code outside the tree.

- Not all Linux systems install Perldoc by default. This is needed for the
  ``--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 *perl-Pod-Perldoc*', while Debian/Ubuntu/Linux
  Mint offer \`perl-doc'.

- 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
  ``/etc/security/limits.conf`` file as root.

Diffing generated code after changes
------------------------------------

When making a change in the code generation area that should not change the
actual emitted code, it is useful to perform a diff to make sure the
emitted code really did not change. To do this, the top level Makefile
provides the *test-snap* and *test-diff* targets:

- Run the test suite with ``make test``
- Take a snapshot with ``make test-snap``
- Apply your changes
- Run the test suite again with ``make test``
- See the changes in the output with ``make test-diff``

Continuous Integration
----------------------

Verilator uses GitHub Actions which automatically tests the master branch
for test failures on new commits. It also runs a daily cron job to validate
all tests against different OS and compiler versions.

Developers can enable Actions on their GitHub repository so that the CI
environment can check their branches too by enabling the build workflow:

- On GitHub, navigate to the main page of the repository.

- Under your repository name, click Actions.

- In the left sidebar, click the workflow you want to enable ("build").

- Click Enable workflow.

Benchmarking
------------

For benchmarking the effects of changes (simulation speed, memory
consumption, Verilation time, etc.), you can use `RTLMeter
<https://github.com/verilator/rtlmeter>`__, a benchmark suite designed for
this purpose. The scripts provided with RTLMeter have many capabilities.
For full details, see the `documentation of RTLMeter
<https://verilator.github.io/rtlmeter>`__ itself.

For a quick check, you an run the following after putting ``verilator`` on
your ``PATH``:

.. code-block:: shell

   ./rtlmeter run --cases "+standard" --workRoot work-a
   ./rtlmeter report work-a

To compare against an alternate version, again put that alternate
``verilator`` on your ``PATH`` then run:

.. code-block:: shell

   ./rtlmeter run --cases "+standard" --workRoot work-b
   ./rtlmeter compare work-a work-b

The continuous integration system in GitHub Actions runs this benchmark
suite nightly on the master branch. The performance numbers from these
nightly runs can be viewed via the `RTLMeter results dashboard
<https://verilator.github.io/verilator-rtlmeter-results>`__. Note that
these results are collected on GitHub hosted runners. These are virtual
machines operating in a potentially noisy environment, so time measurements
can have significant variance. Experience shows that a ~20% time difference
can be reliably measured on GitHub hosted runners, and smaller differences
are noticeable over a few days of reruns as trends emerge from the noise.

Code coverage
-------------

Code coverage for developing Verilator itself can be collected using
``gcc`` and ``gcov`` with the following flow. Note that configuring with
``--enable-dev-gcov`` disables optimization for both the debug and
optimized builds of Verilator, so running the resulting executables can be
slow:

.. code-block:: shell

   ./configure --enable-longtests --enable-dev-gcov
   make -j$(nproc)        # Build verilator
   make test              # Run the tests - this will generate .gcda files
   make coverage-view     # Create and open HTML coverate reprot


The ``coverage-view`` make target opens the generated coverage report. This
depends on ``coverage-report``, which generates the HTML coverage report.
That turn depends on ``coverage-combine``, which combines all ``.gcda``
files into an lcov data file. Each of these make targets can be used
separately if desired.

You can also use the ``coverage-zero`` target to remove all ``.gcda``
files, which in effect clears all collected coverage data. This can be
useful when checking individual test cases while modifying them.

To collect coverage only for select tests, instead of ``make test``, run
the individual ``test_regress/t/*.py`` cases, then use ``make
coverage-view`` as before.

Every time binary built with coverage collection is invoked, it will add
the coverage data collected during that invocation to the existing
``.gcda`` files. This means that ``verilator`` can also be run on any other
external files or projects to collect code coverage on those invocations.

Be aware if changing a test, if that test no longer covers some item, the
report will still contain the old coverage. Use ``make coverage-zero`` and
rerun all tests if this is a concern.

It is also possible to generate a 'patch coverage' report, which will only
contain information about lines modified compared to a Git ref specified by
the ``COVERAGE_BASE`` Make variable (including uncommitted changes). For
example, to see coverage of changes compared to upstream, use:

.. code-block:: shell

   make coverage-view COVERAGE_BASE=origin/master

Fuzzing
-------

There are scripts included to facilitate fuzzing of Verilator. These have
been successfully used to find a number of bugs in the frontend.

The scripts are based on using `American fuzzy lop
<https://lcamtuf.coredump.cx/afl/>`__ on a Debian-like system.

To get started, cd to "nodist/fuzzer/" and run "./all". A sudo password may
be required to setup the system for fuzzing.


Debugging
=========


Debug Levels
------------

The "UINFO" calls in the source indicate a debug level. Messages level 3
and below are globally enabled with ``--debug``. Higher levels may be
controlled with ``--debugi <level>``. An individual source file levels may
be controlled with ``-debugi-<srcfile> <level>``. For example ``--debug
--debugi 5 --debugi-V3Width 9`` will use the debug binary at default debug
level 5, with the V3Width.cpp file at level 9.


`--debug`
---------

When you run with ``--debug``, there are three primary output file types
placed into the obj_dir, .vpp, .tree and .dot files.

.vpp Output
-----------

Verilator creates a *{mod_prefix}*\ __inputs.vpp file containing all the
files that were read, filtered by preprocessing. This file can be fed back
into Verilator, replacing on the command line all of the previous input
files, to enable simplification of test cases. This file also contains most
command line arguments Verilator was invoked as `// verilator fargs``
metacomments, with and can be parsed by `\`-f`. So to reproduce the run
that created the file, run:

::
   verilator -f <prefix>__inputs.vpp <prefix>__inputs.vpp

The first `-f <prefix>__inputs.vpp` reads the command line arguments from
the file. The second `<prefix>__inputsl.vpp` adds the file as a normal
source file.

Verilator also creates .vpp files for each individual file passed on the
command line. These do not contain the command line argument metacomments.


.dot Output
-----------

Dot files are dumps of internal graphs in `GraphViz
<https://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 it can be more useful with large graphs.

For interactive graph viewing consider `xdot
<https://github.com/jrfonseca/xdot.py>`__ or `ZGRViewer
<https://zvtm.sourceforge.net/zgrviewer.html>`__. If you know of better
viewers (especially for large graphs) please let us know.


.tree Output
------------

Tree files are dumps of the AST Tree and are produced between every major
algorithmic stage. An example:

::

     NETLIST 0x90fb00 <e1> {a0ah}
    1: MODULE 0x912b20 <e8822> {a8ah}  top  L2 [P]
   *1:2: VAR 0x91a780 <e74#> {a22ah} @dt=0xa2e640(w32)  out_wide [O] WIRE
    1:2:1: BASICDTYPE 0xa2e640 <e2149> {e24ah} @dt=this(sw32)  integer kwd=integer range=[31:0]

The following summarizes the above example dump, with more detail on each
field in the section below.

+---------------+--------------------------------------------------------+
| ``1:2:``      | The hierarchy of the ``VAR`` is the ``op2p``           |
|               | pointer under the ``MODULE``, which in turn is the     |
|               | ``op1p`` pointer under the ``NETLIST``.                |
+---------------+--------------------------------------------------------+
| ``VAR``       | The AstNodeType (e.g. ``AstVar``).                     |
+---------------+--------------------------------------------------------+
| ``0x91a780``  | Address of this node.                                  |
+---------------+--------------------------------------------------------+
| ``<e74>``     | The 74th edit to the netlist was the last              |
|               | modification to this node.                             |
+---------------+--------------------------------------------------------+
| ``{a22ah}``   | This node is related to the source filename            |
|               | "a", where "a" is the first file read, "z" the 26th,   |
|               | and "aa" the 27th. Then line 22 in that file, then     |
|               | column 8 (aa=0, az=25, ba=26, ...).                    |
+---------------+--------------------------------------------------------+
| ``@dt=0x...`` | The address of the data type this node references.     |
+---------------+--------------------------------------------------------+
| ``w32``       | The data-type width() is 32 bits.                      |
+---------------+--------------------------------------------------------+
| ``out_wide``  | The name() of the node, in this case, the name of the  |
|               | variable.                                              |
+---------------+--------------------------------------------------------+
| ``[O]``       | Flags which vary with the type of node, in this        |
|               | case of a VAR, it means the variable is an output.     |
+---------------+--------------------------------------------------------+

In more detail, the following fields are dumped common to all nodes. They
are produced by the ``AstNode::dump()`` method:

Tree Hierarchy
   The dump lines begin with numbers and colons to indicate the child node
   hierarchy. As noted above, ``AstNode`` has lists of items at the same
   level in the AST, connected by the ``nextp()`` and ``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
      ...

AstNode type
   The textual name of this node AST type (always in capitals). Many of
   these correspond directly to Verilog entities (for example ``MODULE``
   and ``TASK``), but others are internal to Verilator (for example
   ``NETLIST`` and ``BASICDTYPE``).

Address of the node
   A hexadecimal address of the node in memory. Useful for examining with
   the debugger. If the actual address values are not important, then using
   the ``--dump-tree-addrids`` option will convert address values to short
   identifiers of the form ``([A-Z]*)``, which is hopefully easier for the
   reader to cross-reference throughout the dump.

Last edit number
   Of the form ``<ennnn>`` or ``<ennnn#>`` , where ``nnnn`` is the number
   of the last edit to modify this node. The trailing ``#`` indicates the
   node has been edited since the last tree dump (typically in the last
   refinement or optimization pass). GDB can watch for this; see
   `Debugging`.

Source file and line
   Of the form ``{xxnnnn}``, where C{xx} is the filename letter (or
   letters) and ``nnnn`` is the line number within that file. The first
   file is ``a``, the 26th is ``z``, the 27th is ``aa``, and so on.

User pointers
   Shows the value of the node's user1p...user4p, if non-NULL.

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:

   - ``s`` if the node is signed.

   - ``d`` if the node is a double (i.e. a floating point entity).

   - ``w`` always present, indicating this is the width field.

   - ``u`` if the node is unsized.

   - ``/nnnn`` if the node is unsized, where ``nnnn`` is the minimum
        width.

Name of the entity represented by the node if it exists
   For example, for a ``VAR`` is the name of the variable.

Many nodes follow these fields with additional node-specific information.
Thus the ``VARREF`` node will print either ``[LV]`` or ``[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 ``dump()`` method in ``V3AstNodes.cpp`` of the node
type in question to determine additional fields that may be printed.

The ``MODULE`` has a list of ``CELLINLINE`` nodes referred to by its
``op1p()`` pointer, connected by ``nextp()`` and ``prevp()`` pointers.

Similarly, the ``NETLIST`` has a list of modules referred to by its
``op1p()`` pointer.


.tree.json Output
-----------------

``.tree.json``` is an alternative dump format to ``.tree`` that is meant
for programmatic processing (e.g. with `astsee
<https://github.com/antmicro/astsee>`_). To enable this dump format, use
:vlopt:`--dump-tree-json` or :vlopt:`--json-only`.

Structure:

::

   {
     /* Attributes that are common to all types of nodes */
     "type": "VAR",
     "name": "cyc",
     /* By default addresses and filenames use short/stable ids rather than real value */
     "addr": "(H)",
     "loc": "a,25:12,26:15", /* "fileid,firstLine:firstCol,lastLine:endCol" (endCol is right exclusive) */
     "editNum": 602,
     /* Fields that are specific to AstVar nodes:  */
     "origName": "cyc",
     "isSc": false,
     "ioDirection": "NONE",
     "isConst": false,
     "isPullup": false,
     "isPulldown": false,
     "isUsedClock": false,
     "isSigPublic": false,
     "isLatched": false,
     "isUsedLoopIdx": false,
     "noReset": false,
     "attrIsolateAssign": false,
     "attrFileDescr": false,
     "isDpiOpenArray": false,
     "isFuncReturn": false,
     "isFuncLocal": false,
     "attrClocker": "UNKNOWN",
     "lifetime": "NONE",
     "varType": "VAR",
     /* Lists of child nodes (which use similar structure as their parent): */
     "childDTypep": [ /* ... */ ],
     "delayp": [ /* ... */ ],
     "valuep": [ /* ... */ ],
     "attrsp": [ /* ... */ ]
   }

.tree.meta.json Output
----------------------

.tree.meta.json contains metadata that is common across the whole AST tree
(in case of --dump-tree-json, multiple trees share one meta file).

Besides de-duplication of data shared between multiple stages, .meta.json
enables offloading unstable data (that can vary from machine-to-machine or
run-to-run) from main .tree.json. This offloading allows, for example, to
use byte-to-byte comparisons of AST dumps in tests.

::

   {"files": {
     /* Map id to filename, and other metadata */
     "d": {"filename":"/home/ant/tmp/verilator/include/verilated_std.sv", "realpath":"/home/ant/tmp/verilator/include/verilated_std.sv", "language":"1800-2023"},
     "a": {"filename":"<built-in>", "realpath":"<built-in>", "language":"1800-2023"},
     "b": {"filename":"<command-line>", "realpath":"<command-line>", "language":"1800-2023"},
     "c": {"filename":"input.vc", "realpath":"/home/ant/tmp/verilator/test_regress/input.vc", "language":"1800-2023"},
     "e": {"filename":"t/t_EXAMPLE.v", "realpath":"/home/ant/tmp/verilator/test_regress/t/t_EXAMPLE.v", "language":"1800-2023"}
    },"pointers": {
     /* Map id to real address */
     "(AG)": "0x562997289180",
     "(YF)": "0x5629971c50b0",
     "(WF)": "0x5629971e7ae0",
     /* ... /*
    },"ptrFieldNames": [
     /* List of fields that are used for storing pointers */
     "aboveScopep",
     "voidp",
     "addr",
     /* ... */
   ]}


.tree.dot Output
----------------

``*.tree.dot`` files are dumps of the AST Tree in `GraphViz
<https://www.graphviz.org>`__ dot format. This can be used to visualize the
AST Tree. The vertices correspond to ``AstNode`` instances, and the edges
represent the pointers (``op1p``, ``op2p``, etc) between the nodes.


Debugging with GDB
------------------

The `driver.py` script accepts ``--debug --gdb`` to start Verilator under
gdb and break when an error is hit, or the program is about to exit. You
can also use ``--debug --gdbbt`` to just backtrace and then exit gdb. To
debug the Verilated executable, use ``--gdbsim``.

If you wish to start Verilator under GDB (or another debugger), then you
can use ``--debug`` and look at the underlying invocation of
``verilator_dbg``. For example

::

   t/t_alw_dly.py --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 ``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=####

Then, when the watch fires, to break at every following change to that
node:

::

   watch m_editCount

To print a node:

::

   pn nodep
   # or: call dumpGdb(nodep)  # aliased to "pn" in src/.gdbinit
   pnt nodep
   # or: call dumpTreeGdb(nodep)  # aliased to "pnt" in src/.gdbinit

``src/.gdbinit`` and ``src/.gdbinit.py`` define handy utilities for working
with JSON AST dumps. For example:

* ``jstash nodep`` - Perform a JSON AST dump and save it into GDB value
  history (e.g. ``$1``)

* ``jtree nodep`` - Perform a JSON AST dump and pretty print it using
  ``astsee_verilator``.
* ``jtree $1`` - Pretty print a dump that was previously saved by
  ``jstash``.
* ``jtree nodep -d '.file, .timeunit'`` - Perform a JSON AST dump, filter
  out some fields and pretty print it.

* ``jtree 0x55555613dca0`` - Pretty print using address literal (rather
  than actual pointer).
* ``jtree $1 nodep`` - Diff ``nodep`` against an older dump.

A detailed description of ``jstash`` and ``jtree`` can be displayed using
``gdb``'s ``help`` command.

These commands require `astsee <https://github.com/antmicro/astsee>`_ to be
installed.

When GDB halts, it is useful to understand that the backtrace will commonly
show the iterator functions between each invocation of ``visit`` in the
backtrace. You will typically see a frame sequence something like:

::

   ...
   visit()
   iterateChildren()
   iterateAndNext()
   accept()
   visit()
   ...


Adding a New Feature
====================

Generally, what would you do to add a new feature?

1. File an issue (if there isn't already) so others know what you're
   working on.

2. Make a testcase in the test_regress/t/t_EXAMPLE format, see `Testing`.

3. If grammar changes are needed, look at the IEEE 1800-2023 Appendix A, as
   src/verilog.y generally follows the same rule layout.

4. If a new Ast type is needed, add it to the appropriate V3AstNode*.h.
   Follow the convention described above about the AstNode type hierarchy.
   Ordering of definitions is enforced by ``astgen``.

5. Now you can run ``test_regress/t/t_<newtestcase>.py --debug`` and it'll
   probably fail, but you'll see a
   ``test_regress/obj_dir/t_<newtestcase>/*.tree`` file which you can
   examine to see if the parsing worked. See also the sections above on
   debugging.

6. Modify the later visitor functions to process the new feature as needed.


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 ``.cpp`` and ``.h`` files from an existing
pass. You'll need to add a call into your pass from the ``process()``
function in ``src/verilator.cpp``.

To get your pass to build, you'll need to add its binary filename to the
list in ``src/Makefile_obj.in`` and reconfigure.


"Never" features
----------------

Verilator ideally would support all of IEEE, and has the goal to get close
to full support. However the following IEEE sections and features are not
anticipated to be ever implemented for the reasons indicated.

IEEE 1800-2023 3.3 modules within modules
   Little/no tool support, and arguably not a good practice.

IEEE 1800-2023 6.12 "shortreal"
   Little/no tool support, and easily promoted to real.

IEEE 1800-2023 11.11 Min, typ, max
   No SDF support, so will always use typical.

IEEE 1800-2023 20.16 Stochastic analysis
   Little industry use.

IEEE 1800-2023 20.17 PLA modeling
   Little industry use and outdated technology.

IEEE 1800-2023 31 Timing checks
   No longer relevant with static timing analysis tools.

IEEE 1800-2023 32 SDF annotation
   No longer relevant with static timing analysis tools.

IEEE 1800-2023 33 Config
   Little industry use.


Test Driver
===========

This section documents the test driver script, `driver.py`. driver.py
invokes Verilator or another simulator on each test file. For test file
contents description see `Test Language`.

The driver reports the number of tests which pass, fail, or skipped (some
resource required by the test is not available, such as SystemC).

There are thousands of tests, and for faster completion you may want to run
the regression tests with OBJCACHE enabled and in parallel on a machine
with many cores. See the `-j` option and OBJCACHE environment variable.


driver.py Pass-Thru Arguments
-----------------------------

Arguments not understood by `driver.py` which begin with `+verilator+` are
passed through as Verilated executable arguments. Other not-understood
arguments are passed as Verilator arguments.


driver.py Non-Scenario Arguments
--------------------------------

.. program:: driver.py

.. option:: --benchmark [<cycles>]

   Show execution times of each step. If an optional number is given,
   specifies the number of simulation cycles (for tests that support it).

.. option:: --debug

   Same as ``verilator --debug``: Use the debug version of Verilator which
   enables additional assertions, debugging messages, and structure dump
   files.

.. option:: --debugi(-<srcfile>) <level>

   Same as ``verilator --debugi level``: Set Verilator internal debugging
   level globally to the specified debug level (1-10).

.. option:: --driver-clean

   After a test passes, remove the generated objects. Reduces storage
   requirements, but may result in longer runtime if the tests are run
   again.

.. option:: --dump-tree

   Same as ``verilator --dump-tree``: Enable Verilator writing .tree debug
   files with dumping level 3, which dumps the standard critical stages.
   For details on the format see `.tree Output`.

.. option:: --fail-max <numtests>

   Set the number of failing tests, after which the driver will stop
   running additional tests. Defaults to 20, 0 disables.

.. option:: --gdb

   Same as ``verilator --gdb``: Run Verilator under the debugger.

.. option:: --gdbbt

   Same as ``verilator --gdbbt``: Run Verilator under the debugger, only to
   print backtrace information. Requires ``--debug``.

.. option:: --gdbsim

   Run Verilator generated executable under the debugger.

.. option:: --golden

   Update golden files, equivalent to ``export HARNESS_UPDATE_GOLDEN=1``.

.. option:: --hashset <set>/<numsets>

   Split tests based on a hash of the test names into <numsets> and run
   only tests in set number <set> (0..<numsets>-1).

.. option:: --help

   Displays help message and exits.

.. option:: --j #

   Run number of parallel tests, or 0 to determine the count based on the
   number of cores installed.

.. option:: --obj-suffix <name>

   Append the argument to the name of the ``test_regress/obj_``
   directories.

.. option:: --quiet

   Suppress all output except for failures and progress messages every 15
   seconds. Intended for use only in automated regressions. See also
   ``--rerun``, and ``--verbose`` which is not the opposite of ``--quiet``.

.. option:: --rerun

   Rerun all tests that failed in this run. Reruns force the flags
   ``--no-quiet --j 1``.

.. option:: --rr

   Same as ``verilator --rr``: Run Verilator and record with ``rr``.

.. option:: --rrsim

   Run Verilator generated executable and record with ``rr``.

.. option:: --site

   Run site-specific tests also.

.. option:: --stop

   Stop on the first error.

.. option:: --top-filename <file>

   Override the default Verilog file name.

.. option:: --trace

   Set the simulator-specific flags to request waveform tracing.

.. option:: --valgrind

   Same as ``verilator --valgrind``: Run Verilator under `Valgrind <https://valgrind.org/>`_.

.. option:: --verbose

   Compile and run the test in verbose mode. This means ``TEST_VERBOSE``
   will be defined for the test (Verilog and any C++/SystemC wrapper).

.. option:: --verilated-debug

   For tests using the standard C++ wrapper, enable runtime debug mode.


driver.py Scenario Arguments
----------------------------

The following options control which simulator is used, and which tests are
run. Multiple flags may be used to run multiple simulators/scenarios
simultaneously.

.. option:: --atsim

   Run ATSIM simulator tests.

.. option:: --dist

   Run simulator-agnostic distribution tests.

.. option:: --ghdl

   Run GHDL simulator tests.

.. option:: --iv

   Run Icarus Verilog simulator tests.

.. option:: --ms

   Run ModelSim simulator tests.

.. option:: --nc

   Run Cadence NC-Verilog simulator tests.

.. option:: --vcs

   Run Synopsys VCS simulator tests.

.. option:: --vlt

   Run Verilator tests in single-threaded mode. Default unless another
   scenario flag is provided.

.. option:: --vltmt

   Run Verilator tests in multithreaded mode.

.. option:: --xrun

   Run Cadence Xcelium simulator tests.

.. option:: --xsim

   Run Xilinx XSim simulator tests.


driver.py Environment
---------------------

HARNESS_UPDATE_GOLDEN
   If true, update all .out golden reference files. Typically, instead the
   ``--golden`` option is used to update only a single test's reference.

SYSTEMC
   Root directory name of SystemC kit. Only used if ``SYSTEMC_INCLUDE`` not
   set.

SYSTEMC_INCLUDE
   Directory name with systemc.h in it.

VERILATOR_ATSIM
   Command to use to invoke Atsim.

VERILATOR_GHDL
   Command to use to invoke GHDL.

VERILATOR_GDB
   Command to use to invoke GDB debugger.

VERILATOR_IVERILOG
   Command to use to invoke Icarus Verilog.

VERILATOR_MAKE
   Command to use to rebuild Verilator and run single test.

VERILATOR_MODELSIM
   Command to use to invoke ModelSim.

VERILATOR_NCVERILOG
   Command to use to invoke ncverilog.

VERILATOR_ROOT
   Standard path to Verilator distribution root; see primary Verilator
   documentation.

VERILATOR_SOLVER
   SMT solver command for constrained randomization; see primary Verilator
   documentation.

VERILATOR_TESTS_SITE
   Used with ``--site``, a colon-separated list of directories with tests
   to be added to testlist.

VERILATOR_VCS
   Command to use to invoke VCS.

VERILATOR_XELAB
   Command to use to invoke XSim xelab

VERILATOR_XVLOG
   Command to use to invoke XSim xvlog


Test Language
=============

This section describes the format of the ``test_regress/t/*.py`` test
language files, executed by `driver.py`.

Test Language Summary
---------------------

For convenience, a summary of the most commonly used features is provided
here, with a reference in a later section. All test files typically have a
call to the ``test.lint`` or ``test.compile`` methods to compile the test.
For run-time tests, this is followed by a call to the ``test.execute``
method. Both of these functions can optionally be provided with arguments
specifying additional options.

If those complete, the script calls ``test.passes`` to increment the count
of successful tests.

The driver.py script assumes by default that the source Verilog file name
matches the test script name. So a test whose driver is ``t/t_mytest.py``
will expect a Verilog source file ``t/t_mytest.v``. This can be changed
using the ``top_filename`` subroutine, for example

::

   test.top_filename = "t/t_myothertest.v"

By default, all tests will run with major simulators (Icarus Verilog, NC,
VCS, ModelSim, etc.) as well as Verilator, to allow results to be compared.
However, if you wish a test only to be used with Verilator, you can use the
following:

::

   test.scenarios('vlt')

Of the many options that can be set through arguments to ``test.compiler``
and ``test.execute``, the following are particularly useful:

``verilator_flags2``
   A list of flags to be passed to verilator when compiling.

``fails``
   Set true to indicate that the compilation or execution is intended to
   fail.

For example, the following would specify that compilation requires two
defines and is expected to fail.

::

   test.compile(
      verilator_flags2 => ["-DSMALL_CLOCK -DGATED_COMMENT"],
      fails = True)

Hints On Writing Tests
----------------------

There is generally no need for the test to create its own main program or
top level shell as the driver creates one automatically, however some tests
require their own C++ or SystemC test harness. This is commonly given the
same name as the test, but with .cpp as suffix
(``test_regress/t/t_EXAMPLE.cpp``). This can be specified as follows:

::

   test.compile(
      make_top_shell=False,
      make_main=False,
      verilator_flags2=["--exe", test.t_dir + "/" + test.name + ".cpp"])

Tests should be self-checking, rather than producing lots of output. If a
test succeeds it should print ``*-* All Finished *-*`` to standard output
and terminate (in Verilog ``$finish``), if not it should just stop (in
Verilog ``$stop``) as that signals an error.

If termination should be triggered from the C++ wrapper, the following code
can be used:

::

   vl_fatal(__FILE__, __LINE__, "dut", "<error message goes here>");
   exit(1);

Where it might be useful for a test to produce output, it should qualify
this with ``TEST_VERBOSE``. For example in Verilog:

::

   `ifdef TEST_VERBOSE
       $write("Conditional generate if MASK [%1d] = %d\n", g, MASK[g]);
   `endif

Or in a hand-written C++ wrapper:

::

   #ifdef TEST_VERBOSE
      std::cout << "Read a=" << a << std::endl;
   #endif

A filename that should be used to check the output results is given with
``expect_filename``. This should not generally be used to decide if a test
has succeeded. However, in the case of tests that are designed to fail at
compile time, it is the only option. For example:

::

   compile(
      fails=True,
      expect_filename=test.golden_filename)

Note ``expect_filename`` strips some debugging information from the logfile
when comparing.


Test Language Compile/Lint/Run Arguments
----------------------------------------

This section describes common arguments to ``test.compile``, ``test.lint``,
and ``test.run``. The full list of arguments can be found by looking at the
``driver.py`` source code.

all_run_flags
   A list of flags to be passed when running the simulator (Verilated model
   or one of the other simulators).

check_finished
   True to indicate successful completion of the test is indicated by the
   string ``*-* All Finished *-*`` being printed on standard output. This
   is the normal way for successful tests to finish.

fails
   True to indicate this step is expected to fail. Tests that are expected
   to fail generally have _bad in their filename.

make_main
   False to disable the automatic creation of a C++ test wrapper (for
   example when a hand-written test wrapper is provided using ``verilator
   --exe``).

make_top_shell
   False to disable the automatic creation of a top level shell to run the
   executable (for example when a hand-written test wrapper is provided
   using ``verilator --exe``).

ms_flags / ms_flags2 / ms_run_flags
   The equivalent of ``v_flags``, ``v_flags2`` and ``all_run_flags``, but
   only for use with the ModelSim simulator.

nc_flags / nc_flags2 / nc_run_flags
   The equivalent of ``v_flags``, ``v_flags2`` and ``all_run_flags``, but
   only for use with the Cadence NC simulator.

iv_flags / iv_flags2 / iv_run_flags
   The equivalent of ``v_flags``, ``v_flags2`` and ``all_run_flags``, but
   only for use with the Icarus Verilog simulator.

v_flags
   A list of standard Verilog simulator flags to be passed to the simulator
   compiler (Verilator or one of the other simulators). This list is create
   by the driver and rarely changed, use ``v_flags2`` instead.

v_flags2
   A list of standard Verilog simulator flags to be passed to the simulator
   compiler (Verilator or one of the other simulators). Unlike ``v_flags``,
   these options may be overridden in some simulation files.

   Similar sets of flags exist for atsim, GHDL, Cadence NC, ModelSim and
   Synopsys VCS.

vcs_flags / vcs_flags2 / vcs_run_flags
   The equivalent of ``v_flags``, ``v_flags2`` and ``all_run_flags``, but
   only for use with the Synopsys VCS simulator.

verilator_flags / verilator_flags2
   The equivalent of ``v_flags`` and ``v_flags2``, but only for use with
   Verilator. If a flag is a standard flag, ``+incdir`` for example, pass
   it with ``v_flags2`` instead.

xsim_flags / xsim_flags2 / xsim_run_flags
   The equivalent of ``v_flags``, ``v_flags2`` and ``all_run_flags``, but
   only for use with the Xilinx XSim simulator.


Distribution
============

Copyright 2008-2026 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.

SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0

.. |Logo| image:: https://www.veripool.org/img/verilator_256_200_min.png