diff --git a/CMakeLists.txt b/CMakeLists.txt index 537caf740..6c5c282ed 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.003 + VERSION 5.008 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) @@ -118,6 +118,7 @@ install(DIRECTORY include TYPE DATA FILES_MATCHING PATTERN "include/verilated.mk" PATTERN "include/*.[chv]" PATTERN "include/*.cpp" + PATTERN "include/*.sv" PATTERN "include/gtkwave/*.[chv]*" PATTERN "include/vltstd/*.[chv]*" ) diff --git a/Changes b/Changes index 57790292d..583a85abc 100644 --- a/Changes +++ b/Changes @@ -8,7 +8,66 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! -Verilator 5.006 2022-01-22 +Verilator 5.008 2023-03-04 +========================== + +**Minor:** + +* Add --annotate-points option, change multipoint on line reporting (#3876). [Nassim Corteggiani] +* Add --verilate-jobs option (#3889). [Kamil Rakoczy, Antmicro Ltd] +* Add WIDTHEXPAND and WIDTHTRUNC warnings to replace WIDTH (#3900). [Andrew Nolte] +* Add SOURCE_DATE_EPOCH for docs/guide/conf.py (#3918). [Larry Doolittle] +* Add /*verilator public[flat|flat_rd|flat_rw| ]*/ metacomments (#3894). [Joseph Nwabueze] +* Add lint warning on always_comb multidriven (#3888) (#3939). [Adam Bagley] +* Add warning on ++/-- over expressions with potential side effects (#3976). [Krzysztof Boroński] +* Add error on mixing .name and by-port instantiations. +* Removed deprecated --cdc option. +* Support unpacked unions. +* Support interface classes and class implements. +* Support global clocking and $global_clock. +* Support class parameters without initial values. +* Support cast to numbers from strings. +* Support struct I/O in --lib-create (#3378) (#3892). [Varun Koyyalagunta] +* Support function calls without parenthesis (#3903) (#3902). [Ryszard Rozak, Antmicro Ltd] +* Support class extending its parameter (#3904). [Ryszard Rozak, Antmicro Ltd] +* Support static function variables (#3830). [Ryszard Rozak, Antmicro Ltd] +* Support vpiDefName (#3906) (#3931). [Andrew Nolte] +* Support recursive methods (#3987). [Ryszard Rozak, Antmicro Ltd] +* Fix real parameters of infinity and NaN. +* Fix pattern assignment to unpacked structs (#3510). [Mostafa Garnal] +* Fix single-element replication to dynarray/unpacked/queue (#3548). [Gustav Svensk] +* Fix constant enum methods (#3621). [Todd Strader] +* Fix inconsistent naming of generate scope arrays (#3840). [Andrew Nolte] +* Fix namespace fallback resolution (#3863) (#3942). [Aleksander Kiryk, Antmicro Ltd] +* Fix std:: to be parsed first (#3864) (#3928). [Aleksander Kiryk, Antmicro Ltd] +* Fix cmake warning if multiple SOURCES w/o PREFIX (#3916) (#3927). [Yoda Lee] +* Fix paramaterized class function linkage (#3917). [Ryszard Rozak] +* Fix static members of type aliases of a parametrized class (#3922). [Ryszard Rozak, Antmicro Ltd] +* Fix class extend parameter dot case (#3926). [Ryszard Rozak, Antmicro Ltd] +* Fix MsWin missing directory exception, and ::std (#3928) (#3933) (#3935). [Kritik Bhimani] +* Fix very long VPI signal names (#3929). [Marlon James] +* Fix VPI upper interface scopes not found (#3937). [David Stanford] +* Fix virus detection false positive (#3944). [Stuart Morris] +* Fix constant string function assignment (#3945). [Todd Strader] +* Fix constant format field widths (#3946). [Todd Strader] +* Fix class field linking when a super classes is a param (#3949). [Ryszard Rozak, Antmicro Ltd] +* Fix CMake bad C identifiers (#3948) (#3951). [Zixi Li] +* Fix build on HP PA architecture (#3954). [John David Anglin] +* Fix date on the front page of verilator.pdf (#3956) (#3957). [Larry Doolittle] +* Fix dicts declared with ref type (#3960). [Ryszard Rozak, Antmicro Ltd] +* Fix missing error on negative replicate (#3963). [Benjamin Menküc] +* Fix self references to parameterized classes (#3962). [Ryszard Rozak, Antmicro Ltd] +* Fix LITENDIAN warning is backwards (#3966) (#3967). [Cameron Kirk] +* Fix subsequent parameter declarations (#3969). [Ryszard Rozak, Antmicro Ltd] +* Fix timing delays to not truncate below 64 bits (#3973) (#3982). [Felix Neumärker] +* Fix cmake on macOS to mark weak symbols with -U linker flag (#3978) (#3979). [Peter Debacker] +* Fix UNDRIVEN warning seg fault (#3989). [Felix Neumärker] +* Fix coverage of class methods (#3998). [Tim Paine] +* Fix packed array structure replication. +* Fix enum.next(0) and enum.prev(0). + + +Verilator 5.006 2023-01-22 ========================== **Minor:** @@ -20,6 +79,7 @@ Verilator 5.006 2022-01-22 * Support property calls without parenthesis (#3879) (#3893). [Ryszard Rozak, Antmicro Ltd] * Support import/export lists in modport (#3886). [Gökçe Aydos] * Support class queue equality (#3895). [Ilya Barkov] +* Support type case and type equality comparisons. * Add IMPLICITSTATIC warning when a ftask/function is implicitly static (#3839). [Ryszard Rozak, Antmicro Ltd] * Add VL_VALUE_STRING_MAX_WORDS override (#3869). [Andrew Nolte] * Optimize expansion of extend operators. @@ -44,6 +104,8 @@ Verilator 5.006 2022-01-22 * Fix foreach unnamedblk duplicate error (#3885). [Ilya Barkov] * Fix elaboration of member selected classes (#3890). [Ilya Barkov] * Fix mismatched widths in DFG (#3872). [Geza Lore, Yike Zhou] +* Fix lint for non-integral types in packed structs. +* Fix generate case with empty body statements. Verilator 5.004 2022-12-14 diff --git a/Makefile.in b/Makefile.in index ba14a84d7..c845f5e76 100644 --- a/Makefile.in +++ b/Makefile.in @@ -15,13 +15,13 @@ # #****************************************************************************/ # -# make all to compile and build Verilator. -# make install to install it. -# make TAGS to update tags tables. +# make all to compile and build Verilator. +# make install to install it. +# make TAGS to update tags tables. # # make clean or make mostlyclean # Delete all files from the current directory that are normally -# created by building the program. Don't delete the files that +# created by building the program. Don't delete the files that # record the configuration. Also preserve files that could be made # by building, but normally aren't because the distribution comes # with them. @@ -153,7 +153,7 @@ msg_test: all_nomsg @echo .PHONY: test -ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users +ifeq ($(CFG_WITH_LONGTESTS),yes) # Local... Else don't burden users test: smoke-test test_regress # examples is part of test_regress's test_regress/t/t_a2_examples.pl # (because that allows it to run in parallel with other test_regress's) @@ -462,7 +462,7 @@ config.status: configure ./config.status --recheck configure: configure.ac -ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users +ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users autoconf --warnings=all else autoconf @@ -501,7 +501,7 @@ distclean maintainer-clean:: TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \ ${srcdir}/*.in ${srcdir}/*.pod -TAGS: $(TAGFILES) +TAGS: $(TAGFILES) etags $(TAGFILES) .PHONY: doxygen diff --git a/bin/verilator b/bin/verilator index 7d4c84bd4..587a9b85f 100755 --- a/bin/verilator +++ b/bin/verilator @@ -362,7 +362,7 @@ detailed descriptions of these arguments. +incdir+ Directory to search for includes --inline-mult Tune module inlining --instr-count-dpi Assumed dynamic instruction count of DPI imports - -j Parallelism for --build (alias to --build-jobs) + -j Parallelism for --build-jobs/--verilate-jobs --l2-name Verilog scope name of the top module --language Default language standard to parse -LDFLAGS Linker pre-object arguments for makefile @@ -416,6 +416,7 @@ detailed descriptions of these arguments. --no-skip-identical Disable skipping identical output --stats Create statistics file --stats-vars Provide statistics on variables + --no-std Prevent parsing standard library --structs-packed Convert all unpacked structures to packed structures -sv Enable SystemVerilog parsing +systemverilogext+ Synonym for +1800-2017ext+ @@ -445,6 +446,7 @@ detailed descriptions of these arguments. --unused-regexp Tune UNUSED lint signals -V Verbose version and config -v Verilog library + --verilate-jobs Job threads for Verilation stage --no-verilate Skip Verilation and just compile previously Verilated code +verilog1995ext+ Synonym for +1364-1995ext+ +verilog2001ext+ Synonym for +1364-2001ext+ diff --git a/bin/verilator_coverage b/bin/verilator_coverage index 92f1a7c20..19493d44b 100755 --- a/bin/verilator_coverage +++ b/bin/verilator_coverage @@ -169,6 +169,7 @@ L. --annotate Directory name for source annotation. --annotate-all All files should be shown. --annotate-min Minimum occurrence count for uncovered. + --annotate-points Annotates info from each coverage point. --help Displays this message and version and exits. --rank Compute relative importance of tests. --unlink With --write, unlink all inputs diff --git a/bin/verilator_difftree b/bin/verilator_difftree index f298bcf07..63112a592 100755 --- a/bin/verilator_difftree +++ b/bin/verilator_difftree @@ -42,8 +42,8 @@ def diff_dir(a, b): continue a = files[base]['a'] b = files[base]['b'] - print("=" * 70) - print("= %s <-> %s" % (a, b)) + print("=" * 70, flush=True) + print("= %s <-> %s" % (a, b), flush=True) diff_file(a, b) anyfile = True if not anyfile: diff --git a/ci/ci-win-compile.ps1 b/ci/ci-win-compile.ps1 index 20a744539..e4146b033 100644 --- a/ci/ci-win-compile.ps1 +++ b/ci/ci-win-compile.ps1 @@ -4,12 +4,12 @@ if (-Not (Test-Path $PWD/../.ccache/win_bison.exe)) { mkdir build cd build cmake .. --install-prefix $PWD/../../../.ccache - cmake --build . --config Release + cmake --build . --config Release -j 3 cmake --install . --prefix $PWD/../../../.ccache cd ../.. } mkdir build cd build cmake .. --install-prefix $PWD/../install -cmake --build . --config Release +cmake --build . --config Release -j 3 cmake --install . --prefix $PWD/../install diff --git a/ci/ci-win-test.ps1 b/ci/ci-win-test.ps1 index 1900bd4a5..1406126d6 100644 --- a/ci/ci-win-test.ps1 +++ b/ci/ci-win-test.ps1 @@ -4,7 +4,7 @@ cd examples/cmake_tracing_c mkdir build cd build cmake .. -cmake --build . --config Release +cmake --build . --config Release -j 3 Release/example.exe cd .. Remove-Item -path build -recurse diff --git a/configure.ac b/configure.ac index d3be24f47..74d1beb5b 100644 --- a/configure.ac +++ b/configure.ac @@ -5,12 +5,12 @@ # General Public License Version 3 or the Perl Artistic License Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -# When releasing, also update header of Changes file +# When releasing, also update header of Changes file, # and commit using "devel release" or "Version bump" message # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.006 2023-01-22], +AC_INIT([Verilator],[5.008 2023-03-04], [https://verilator.org], [verilator],[https://verilator.org]) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index ed105e78f..aad4beb04 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -3,6 +3,7 @@ under the Developer Certificate of Origin (https://developercertificate.org/). Please see the Verilator manual for 200+ additional contributors. Thanks to all. +Adam Bagley Adrien Le Masle Ahmed El-Mahmoudy Aleksander Kiryk @@ -13,6 +14,7 @@ Ameya Vikram Singh Andreas Kuster Andrew Nolte Arkadiusz Kozdra +Cameron Kirk Chris Randall Chuxuan Wang Conor McCullough @@ -28,6 +30,7 @@ Driss Hafdi Edgar E. Iglesias Eric Rippey Fan Shupei +Felix Neumärker Felix Yan Garrett Smith Geza Lore @@ -65,6 +68,7 @@ Joey Liu John Coiner John Demme Jonathan Drolet +Joseph Nwabueze Josh Redford Julie Schwartz Julien Margetts @@ -75,6 +79,7 @@ Keith Colbert Kevin Kiningham Kritik Bhimani Krzysztof Bieganski +Krzysztof Boroński Kuba Ober Larry Doolittle Ludwig Rogiers @@ -103,6 +108,7 @@ Nathan Myers Patrick Stewart Paul Wright Pawel Sagan +Peter Debacker Peter Horvath Peter Monsson Philipp Wagner @@ -148,3 +154,4 @@ Yutetsu TAKATSUKASA Yu-Sheng Lin Yves Mathieu Zhanglei Wang +Zixi Li diff --git a/docs/gen/ex_WIDTH_1_faulty.rst b/docs/gen/ex_WIDTHEXPAND_1_faulty.rst similarity index 75% rename from docs/gen/ex_WIDTH_1_faulty.rst rename to docs/gen/ex_WIDTHEXPAND_1_faulty.rst index 0121e66ac..08c1f0ba2 100644 --- a/docs/gen/ex_WIDTH_1_faulty.rst +++ b/docs/gen/ex_WIDTHEXPAND_1_faulty.rst @@ -1,4 +1,4 @@ -.. comment: generated by t_lint_width_docs_bad +.. comment: generated by t_lint_widthexpand_docs_bad .. code-block:: sv :linenos: :emphasize-lines: 3 diff --git a/docs/gen/ex_WIDTH_1_fixed.rst b/docs/gen/ex_WIDTHEXPAND_1_fixed.rst similarity index 66% rename from docs/gen/ex_WIDTH_1_fixed.rst rename to docs/gen/ex_WIDTHEXPAND_1_fixed.rst index 11a33b7d0..b40b8b2a6 100644 --- a/docs/gen/ex_WIDTH_1_fixed.rst +++ b/docs/gen/ex_WIDTHEXPAND_1_fixed.rst @@ -1,4 +1,4 @@ -.. comment: generated by t_lint_width_docs_bad +.. comment: generated by t_lint_widthexpand_docs_bad .. code-block:: sv :emphasize-lines: 1 diff --git a/docs/gen/ex_WIDTHEXPAND_1_msg.rst b/docs/gen/ex_WIDTHEXPAND_1_msg.rst new file mode 100644 index 000000000..927476284 --- /dev/null +++ b/docs/gen/ex_WIDTHEXPAND_1_msg.rst @@ -0,0 +1,4 @@ +.. comment: generated by t_lint_widthexpand_docs_bad +.. code-block:: + + %Warning-WIDTHEXPAND: example.v:3:29 Bit extraction of array[4:0] requires 3 bit index, not 2 bits. diff --git a/docs/gen/ex_WIDTH_1_msg.rst b/docs/gen/ex_WIDTH_1_msg.rst deleted file mode 100644 index 276a8ffc6..000000000 --- a/docs/gen/ex_WIDTH_1_msg.rst +++ /dev/null @@ -1,4 +0,0 @@ -.. comment: generated by t_lint_width_docs_bad -.. code-block:: - - %Warning-WIDTH: example.v:3:29 Bit extraction of array[4:0] requires 3 bit index, not 2 bits. diff --git a/docs/guide/conf.py b/docs/guide/conf.py index bcf574cc7..8755706ed 100644 --- a/docs/guide/conf.py +++ b/docs/guide/conf.py @@ -10,7 +10,6 @@ # ---------------------------------------------------------------------- # -- Path setup -from datetime import datetime import os import re import sys @@ -24,10 +23,18 @@ def get_vlt_version(): filename = "../../Makefile" with open(filename, "r", encoding="utf8") as fh: for line in fh: - match = re.search(r"PACKAGE_VERSION_NUMBER *= *([a-z0-9.]+)", line) + match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +([-0-9]+)", + line) if match: - return match.group(1) - return "unknown" + return match.group(1), match.group(2) + match = re.search(r"PACKAGE_VERSION *= *([a-z0-9.]+) +devel", line) + if match: + try: + data = os.popen('git log -n 1 --pretty=%cs').read() + except Exception: + data = "" # fallback, and Sphinx will fill in today's date + return "Devel " + match.group(1), data + return "unknown", "unknown" def setup(app): @@ -44,8 +51,8 @@ author = 'Wilson Snyder' # The master toctree document. master_doc = "index" -version = get_vlt_version() -release = get_vlt_version() +version, today_fmt = get_vlt_version() +release = version rst_prolog = """ .. role:: vlopt(option) @@ -89,9 +96,6 @@ source_suffix = [".rst"] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] -# Date format to ISO -today_fmt = datetime.now().strftime("%F") - # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True diff --git a/docs/guide/connecting.rst b/docs/guide/connecting.rst index 35c1c6aec..9762e264a 100644 --- a/docs/guide/connecting.rst +++ b/docs/guide/connecting.rst @@ -374,9 +374,11 @@ changed on the specified clock edge. .. code-block:: bash cat >our.v <<'EOF' - module our (input clk); - reg readme /*verilator public_flat_rd*/; - reg writeme /*verilator public_flat_rw @(posedge clk) */; + module our #( + parameter WIDTH /*verilator public_flat_rd*/ = 32 + ) (input clk); + reg [WIDTH-1:0] readme /*verilator public_flat_rd*/; + reg [WIDTH-1:0] writeme /*verilator public_flat_rw @(posedge clk) */; initial $finish; endmodule EOF @@ -398,12 +400,14 @@ accesses the above signal "readme" would be: vpiHandle vh1 = vpi_handle_by_name((PLI_BYTE8*)"TOP.our.readme", NULL); if (!vh1) vl_fatal(__FILE__, __LINE__, "sim_main", "No handle found"); const char* name = vpi_get_str(vpiName, vh1); - printf("Module name: %s\n", name); // Prints "readme" + const char* type = vpi_get_str(vpiType, vh1); + const int size = vpi_get(vpiSize, vh1); + printf("register name: %s, type: %s, size: %d\n", name, type, size); // Prints "register name: readme, type: vpiReg, size: 32" s_vpi_value v; v.format = vpiIntVal; vpi_get_value(vh1, &v); - printf("Value of v: %d\n", v.value.integer); // Prints "readme" + printf("Value of %s: %d\n", name, v.value.integer); // Prints "Value of readme: 0" } int main(int argc, char** argv) { @@ -479,11 +483,12 @@ distribution. Verilated and VerilatedContext ============================== -Multiple Verilated models may be part of the same simulation context, that -is share a VPI interface, sense of time, and common settings. This common -simulation context information is stored in a ``VerilatedContext`` +Multiple C++ Verilated models may be part of the same simulation context, +that is share a VPI interface, sense of time, and common settings. This +common simulation context information is stored in a ``VerilatedContext`` structure. If a ``VerilatedContext`` is not created prior to creating a -model, a default global one is created automatically. +model, a default global one is created automatically. SystemC requires +using only the single, default VerilatedContext. The ``Verilated::`` methods, including the ``Verilated::commandArgs`` call shown above, call VerilatedContext methods using the default global diff --git a/docs/guide/deprecations.rst b/docs/guide/deprecations.rst index eb3f05f2c..1fd8252fd 100644 --- a/docs/guide/deprecations.rst +++ b/docs/guide/deprecations.rst @@ -22,10 +22,6 @@ Verilated_heavy.h "verilated.h". Verilated_heavy.h is planned for removal no sooner than July 2022. -Option `--cdc` - The experimental `--cdc` option is believed to be generally unused and is - planned for removal no sooner than January 2023. - Option `-O` The debug `-O` options have been replaced with `-fno-` debug options to match GCC. The old options are diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index e610fa926..0a4b90249 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -155,18 +155,6 @@ Summary: Specify C++ without SystemC output mode; see also the :vlopt:`--sc` option. -.. option:: --cdc - - Permanently experimental. Perform some clock domain crossing checks and - issue related warnings (CDCRSTLOGIC) and then exit; if warnings other - than CDC warnings are needed, make a second run with - :vlopt:`--lint-only`. Additional warning information is also written to - the file :file:`__cdc.txt`. - - Currently only checks some items that other CDC tools missed; if you are - interested in adding more traditional CDC checks, please contact the - authors. - .. option:: -CFLAGS Add specified C compiler argument to the generated makefiles. For @@ -434,7 +422,7 @@ Summary: Preprocess the source code, but do not compile, similar to C++ preprocessing using :command:`gcc -E`. Output is written to standard out. Beware of enabling debugging messages, as they will also go to - standard out. + standard out. See :vlopt:`--no-std`, which is implied by this. See also :vlopt:`--dump-defines`, :vlopt:`-P`, and :vlopt:`--pp-comments` options. @@ -707,9 +695,10 @@ Summary: .. option:: -j [] Specify the level of parallelism for :vlopt:`--build` if - :vlopt:`--build-jobs` isn't provided. If zero, uses the number of threads - in the current hardware. Otherwise, the must be a positive - integer specifying the maximum number of parallel build jobs. + :vlopt:`--build-jobs` isn't provided, and the internal compilation steps + of Verilator if :vlopt:`--verilate-jobs` isn't provided. If zero, uses + the number of threads in the current hardware. Otherwise, must be a + positive integer specifying the maximum number of parallel build jobs. .. option:: --l2-name @@ -1201,6 +1190,10 @@ Summary: by size (plain :vlopt:`--stats` just gives a count). See :vlopt:`--stats`, which is implied by this. +.. option:: --no-std + + Prevents parsing standard library. + .. option:: --structs-packed Converts all unpacked structures to packed structures, and issues an @@ -1429,6 +1422,15 @@ Summary: execute only the build. This can be useful for rebuilding the Verilated code produced by a previous invocation of Verilator. +.. option:: --verilate-jobs [] + + Specify the level of parallelism for the internal compilation steps of + Verilator. If zero, uses the number of threads in the current hardware. + Otherwise, must be a positive integer specifying the maximum number of + parallel build jobs. + + See also :vlopt:`-j`. + .. option:: +verilog1995ext+ Synonym for :vlopt:`+1364-1995ext+\`. @@ -1528,6 +1530,8 @@ Summary: :command:`gcc -Wpedantic`. Rarely used, and intended only for strict compliance tests. + This option changes :option:`ASSIGNIN` from an error to a warning. + .. option:: -Wwarn- Enables the specified warning message. diff --git a/docs/guide/exe_verilator_coverage.rst b/docs/guide/exe_verilator_coverage.rst index 57eb02808..2c78cf7de 100644 --- a/docs/guide/exe_verilator_coverage.rst +++ b/docs/guide/exe_verilator_coverage.rst @@ -6,10 +6,10 @@ verilator_coverage Verilator_coverage processes Verilated model-generated coverage reports. -With --annotate, it reads the specified coverage data file and generates -annotated source code with coverage metrics annotated. If multiple -coverage points exist on the same source code line, additional lines will -be inserted to report the additional points. +With `--annotate`, it reads the specified coverage data file and generates +annotated source code with coverage metrics annotated. With +`--annotate-points` the coverage points corresponding to each line are also +shown. Additional Verilog-XL-style standard arguments specify the search paths necessary to find the source code on which the coverage analysis was @@ -58,6 +58,18 @@ to read multiple inputs. If no data file is specified, by default, Specifies the directory name to which source files with annotated coverage data should be written. +Converting from the Verilator coverage data format to the info format is +lossy; the info will have all forms of coverage merged line coverage, and +if there are multiple coverage points on a single line they will merge. +The minimum coverage across all merged points will be used to report +coverage of the line. + +The first character of the line shows a summary of the coverage; this +allows use of grep to filter the report. `%` indicates at least one point +on the line was below the coverage limit. `+` indicates an +:option:`--annotate-points` point was at or above the limit, and `-` that +the point was below the limit. + .. option:: --annotate-all Specifies all files should be shown. By default, only those source files @@ -70,6 +82,13 @@ coverage hits, then the coverage point will be considered above the threshold, and the coverage report will put a "%" to indicate the coverage is insufficient. Defaults to 10. +.. option:: --annotate-points + +Specifies all coverage points should be shown after each line of text. By +default, only source lines are shown. + +with low coverage are written to the output directory. + .. option:: --help Displays a help summary, the program version, and exits. diff --git a/docs/guide/extensions.rst b/docs/guide/extensions.rst index 6f71cf947..5994fb770 100644 --- a/docs/guide/extensions.rst +++ b/docs/guide/extensions.rst @@ -446,6 +446,33 @@ or "`ifdef`"'s may break other tools. Same as :option:`public_flat_rw` configuration file option. +.. option:: /*verilator&32;public_[|flat|flat_rd|flat_rw]_on [@()]*/ (as scope) + + Used to wrap multiple signals and parameters with the respective public attribute. + See attribute above for their respective behavior. Cannot be nested. e.g: + + .. code-block:: sv + + /*verilator public_flat_rw_on*/ + logic clk; + logic rst; + parameter width = 8; + /* verilator public_off*/ + logic data; + + Is equivalent to: + + .. code-block:: sv + + logic clk /*verilator public_flat_rw*/; + logic rst /*verilator public_flat_rw*/; + parameter width /*verilator public_flat_rw*/ = 8; + logic data; + +.. option:: /*verilator&32;public_off*/ + + Terminates the previous `/*verilator public*_on*/` directive; see above. + .. option:: /*verilator&32;public_module*/ Used after a module statement to indicate the module should not be diff --git a/docs/guide/languages.rst b/docs/guide/languages.rst index 4865f5375..6eeb84fb1 100644 --- a/docs/guide/languages.rst +++ b/docs/guide/languages.rst @@ -461,6 +461,10 @@ chandle Treated as a "longint"; does not yet warn about operations specified as illegal on chandles. +checker + Treated as a "module"; does not yet warn about many constructs illegal + inside a checker. + disable Disable statements may be used only if the block being disabled is a block the disable statement itself is inside. This was commonly used to diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 7f0011153..ccfb0e763 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -74,7 +74,8 @@ List Of Warnings .. option:: Unsupported: .... This error indicates that the code uses a Verilog language construct - that is not yet supported in Verilator. See the Limitations chapter. + that is not yet supported in Verilator. See also :ref:`Language + Limitations`. .. option:: ALWCOMBORDER @@ -317,9 +318,11 @@ List Of Warnings .. option:: CDCRSTLOGIC - With :vlopt:`--cdc` only, it warns that asynchronous flop reset terms come - from other than primary inputs or flopped outputs, creating the - potential for reset glitches. + Historical, never issued since version 5.008. + + Warned with a no longer supported clock domain crossing option that + asynchronous flop reset terms came from other than primary inputs or + flopped outputs, creating the potential for reset glitches. .. option:: CLKDATA @@ -847,14 +850,14 @@ List Of Warnings .. TODO better example - Warns that a packed vector is declared with little endian bit numbering - (i.e. [0:7]). Big endian bit numbering is now the overwhelming - standard, and little numbering is now thus often due to simple oversight + Warns that a packed vector is declared with big endian bit numbering + (i.e. [0:7]). Little endian bit numbering is now the overwhelming + standard, and big numbering is now thus often due to simple oversight instead of intent. - It also warns that an instance is declared with little endian range - (i.e. [0:7] or [7]) and is connected to an N-wide signal. Based on IEEE - the bits will likely be backward from what people may expect + It also warns that an instance is declared with big endian range + (i.e. [0:7] or [7]) and is connected to an N-wide signal. + The bits will likely be backward from what people may expect (i.e., instance [0] will connect to signal bit [N-1] not bit [0]). Ignoring this warning will only suppress the lint check; it will @@ -1790,16 +1793,27 @@ List Of Warnings For example, this is a missized index: - .. include:: ../../docs/gen/ex_WIDTH_1_faulty.rst + .. include:: ../../docs/gen/ex_WIDTHEXPAND_1_faulty.rst - Results in: + Results in a WIDTHEXPAND warning: - .. include:: ../../docs/gen/ex_WIDTH_1_msg.rst + .. include:: ../../docs/gen/ex_WIDTHEXPAND_1_msg.rst One possible fix: - .. include:: ../../docs/gen/ex_WIDTH_1_fixed.rst + .. include:: ../../docs/gen/ex_WIDTHEXPAND_1_fixed.rst +.. option:: WIDTHTRUNC + + A more granular WIDTH warning, for when a value is truncated + +.. option:: WIDTHEXPAND + + A more granular WIDTH warning, for when a value is zero expanded + +.. option:: WIDTHXZEXPAND + + A more granular WIDTH warning, for when a value is xz expanded .. option:: WIDTHCONCAT diff --git a/examples/cmake_hello_c/CMakeLists.txt b/examples/cmake_hello_c/CMakeLists.txt index 09abc8016..679abcc33 100644 --- a/examples/cmake_hello_c/CMakeLists.txt +++ b/examples/cmake_hello_c/CMakeLists.txt @@ -19,7 +19,8 @@ # cmake .. # cmake --build . -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0074 NEW) project(cmake_hello_c) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) diff --git a/examples/cmake_hello_sc/CMakeLists.txt b/examples/cmake_hello_sc/CMakeLists.txt index f85d05c6d..16978bc80 100644 --- a/examples/cmake_hello_sc/CMakeLists.txt +++ b/examples/cmake_hello_sc/CMakeLists.txt @@ -19,7 +19,8 @@ # cmake .. # cmake --build . -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0074 NEW) project(cmake_hello_sc CXX) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) diff --git a/examples/cmake_protect_lib/CMakeLists.txt b/examples/cmake_protect_lib/CMakeLists.txt index de2de27c2..1e09cb5fd 100644 --- a/examples/cmake_protect_lib/CMakeLists.txt +++ b/examples/cmake_protect_lib/CMakeLists.txt @@ -19,7 +19,8 @@ # cmake .. # cmake --build . -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0074 NEW) project(cmake_protect_lib) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) diff --git a/examples/cmake_tracing_c/CMakeLists.txt b/examples/cmake_tracing_c/CMakeLists.txt index 95fb3dfb2..3f69fc3c9 100644 --- a/examples/cmake_tracing_c/CMakeLists.txt +++ b/examples/cmake_tracing_c/CMakeLists.txt @@ -19,7 +19,8 @@ # cmake .. # cmake --build . -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0074 NEW) project(cmake_tracing_c) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) diff --git a/examples/cmake_tracing_sc/CMakeLists.txt b/examples/cmake_tracing_sc/CMakeLists.txt index 0d67a8cf5..58d0aaceb 100644 --- a/examples/cmake_tracing_sc/CMakeLists.txt +++ b/examples/cmake_tracing_sc/CMakeLists.txt @@ -19,7 +19,9 @@ # cmake .. # cmake --build . -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0074 NEW) + project(cmake_tracing_sc_example CXX) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) diff --git a/examples/make_tracing_c/Makefile_obj b/examples/make_tracing_c/Makefile_obj index 56db2ee15..d91039d21 100644 --- a/examples/make_tracing_c/Makefile_obj +++ b/examples/make_tracing_c/Makefile_obj @@ -31,7 +31,7 @@ CPPFLAGS += -DVL_DEBUG=1 # Turn on some more compiler lint flags (when configured appropriately) # For testing inside Verilator, "configure --enable-ccwarn" will do this # automatically; otherwise you may want this unconditionally enabled -ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users +ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users USER_CPPFLAGS_WALL += -W -Werror -Wall endif diff --git a/examples/make_tracing_sc/Makefile_obj b/examples/make_tracing_sc/Makefile_obj index a2d175a27..be55d066c 100644 --- a/examples/make_tracing_sc/Makefile_obj +++ b/examples/make_tracing_sc/Makefile_obj @@ -30,7 +30,7 @@ CPPFLAGS += -Wno-deprecated # Turn on some more flags (when configured appropriately) # For testing inside Verilator, "configure --enable-ccwarn" will do this # automatically; otherwise you may want this unconditionally enabled -ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users +ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users USER_CPPFLAGS_WALL += -W -Werror -Wall endif diff --git a/include/verilated.cpp b/include/verilated.cpp index 2b1c6f997..995656840 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -1411,6 +1411,12 @@ IData VL_FERROR_IN(IData, std::string& outputr) VL_MT_SAFE { outputr = std::string{::std::strerror(ret)}; return ret; } +IData VL_FERROR_IW(IData fpi, int obits, WDataOutP outwp) VL_MT_SAFE { + std::string output; + const IData ret = VL_FERROR_IN(fpi, output /*ref*/); + _vl_string_to_vint(obits, outwp, output.length(), output.c_str()); + return ret; +} IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) { return Verilated::threadContextp()->impp()->fdNew(filename.c_str(), mode.c_str()); @@ -1793,6 +1799,7 @@ std::string VL_TO_STRING(CData lhs) { return VL_SFORMATF_NX("'h%0x", 8, lhs); } std::string VL_TO_STRING(SData lhs) { return VL_SFORMATF_NX("'h%0x", 16, lhs); } std::string VL_TO_STRING(IData lhs) { return VL_SFORMATF_NX("'h%0x", 32, lhs); } std::string VL_TO_STRING(QData lhs) { return VL_SFORMATF_NX("'h%0x", 64, lhs); } +std::string VL_TO_STRING(double lhs) { return VL_SFORMATF_NX("%d", 64, lhs); } std::string VL_TO_STRING_W(int words, const WDataInP obj) { return VL_SFORMATF_NX("'h%0x", words * VL_EDATASIZE, obj); } @@ -1861,6 +1868,33 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE { if (errno != 0) v = 0; return static_cast(v); } +IData VL_NTOI_I(int obits, const std::string& str) VL_PURE { return VL_NTOI_Q(obits, str); } +QData VL_NTOI_Q(int obits, const std::string& str) VL_PURE { + QData out = 0; + const size_t procLen = std::min(str.length(), static_cast(8)); + const char* const datap = str.data(); + int pos = static_cast(str.length()) - 1; + int bit = 0; + while (bit < obits && pos >= 0) { + out |= static_cast(datap[pos]) << VL_BITBIT_Q(bit); + bit += 8; + --pos; + } + return out & VL_MASK_Q(obits); +} +void VL_NTOI_W(int obits, WDataOutP owp, const std::string& str) VL_PURE { + const int words = VL_WORDS_I(obits); + for (int i = 0; i < words; ++i) owp[i] = 0; + const char* const datap = str.data(); + int pos = static_cast(str.length()) - 1; + int bit = 0; + while (bit < obits && pos >= 0) { + owp[VL_BITWORD_I(bit)] |= static_cast(datap[pos]) << VL_BITBIT_I(bit); + bit += 8; + --pos; + } + owp[words - 1] &= VL_MASK_E(obits); +} //=========================================================================== // Readmem/writemem @@ -2948,7 +2982,7 @@ VerilatedModule::~VerilatedModule() { // VerilatedVar:: Methods // cppcheck-suppress unusedFunction // Used by applications -uint32_t VerilatedVarProps::entSize() const { +uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE { uint32_t size = 1; switch (vltype()) { case VLVT_PTR: size = sizeof(void*); break; @@ -2968,7 +3002,7 @@ size_t VerilatedVarProps::totalSize() const { return size; } -void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const { +void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE { if (VL_UNLIKELY(dim <= 0 || dim > udims())) return nullptr; if (VL_UNLIKELY(indx < low(dim) || indx > high(dim))) return nullptr; const int indxAdj = indx - low(dim); @@ -3087,7 +3121,7 @@ void* VerilatedScope::exportFindNullError(int funcnum) VL_MT_SAFE { return nullptr; } -void* VerilatedScope::exportFindError(int funcnum) const { +void* VerilatedScope::exportFindError(int funcnum) const VL_MT_SAFE { // Slowpath - Called only when find has failed const std::string msg = (std::string{"Testbench C called '"} + VerilatedImp::exportName(funcnum) diff --git a/include/verilated.h b/include/verilated.h index 0b4592b27..822fc89fa 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -47,6 +47,7 @@ #include #include #include +#include #include #include #include @@ -175,6 +176,19 @@ public: void unlock() VL_RELEASE() VL_MT_SAFE { m_mutex.unlock(); } /// Try to acquire mutex. Returns true on success, and false on failure. bool try_lock() VL_TRY_ACQUIRE(true) VL_MT_SAFE { return m_mutex.try_lock(); } + /// Acquire/lock mutex and check for stop request + /// It tries to lock the mutex and if it fails, it check if stop request was send. + /// It returns after locking mutex. + /// This function should be extracted to V3ThreadPool, but due to clang thread-safety + /// limitations it needs to be placed here. + void lockCheckStopRequest(std::function checkStopRequestFunction) + VL_ACQUIRE() VL_MT_SAFE { + while (true) { + checkStopRequestFunction(); + if (m_mutex.try_lock()) return; + VL_CPU_RELAX(); + } + } }; /// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks @@ -192,10 +206,19 @@ public: } /// Destruct and unlock the mutex ~VerilatedLockGuard() VL_RELEASE() { m_mutexr.unlock(); } - /// Unlock the mutex - void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); } /// Lock the mutex + void lock() VL_ACQUIRE() VL_MT_SAFE { m_mutexr.lock(); } + /// Unlock the mutex void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); } + /// Acquire/lock mutex and check for stop request. + /// It tries to lock the mutex and if it fails, it check if stop request was send. + /// It returns after locking mutex. + /// This function should be extracted to V3ThreadPool, but due to clang thread-safety + /// limitations it needs to be placed here. + void lockCheckStopRequest(std::function checkStopRequestFunction) + VL_ACQUIRE() VL_MT_SAFE { + m_mutexr.lockCheckStopRequest(checkStopRequestFunction); + } }; // Internals: Remember the calling thread at construction time, and make @@ -624,7 +647,7 @@ public: // But internals only - called from VerilatedModule's VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT; VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; } void scopeDump() const; - void* exportFindError(int funcnum) const; + void* exportFindError(int funcnum) const VL_MT_SAFE; static void* exportFindNullError(int funcnum) VL_MT_SAFE; static void* exportFind(const VerilatedScope* scopep, int funcnum) VL_MT_SAFE { if (VL_UNLIKELY(!scopep)) return exportFindNullError(funcnum); diff --git a/include/verilated.mk.in b/include/verilated.mk.in index 8e040cd79..56257b9f4 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -67,7 +67,7 @@ VK_CPPFLAGS_ALWAYS += \ -DVM_TRACE_VCD=$(VM_TRACE_VCD) \ $(CFG_CXXFLAGS_NO_UNUSED) \ -ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users +ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users VK_CPPFLAGS_WALL += -Wall $(CFG_CXXFLAGS_WEXTRA) -Werror endif diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 013193354..bf39e3c12 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -2164,6 +2164,9 @@ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool igno } extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE; +extern IData VL_NTOI_I(int obits, const std::string& str) VL_PURE; +extern QData VL_NTOI_Q(int obits, const std::string& str) VL_PURE; +extern void VL_NTOI_W(int obits, WDataOutP owp, const std::string& str) VL_PURE; extern IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE; @@ -2212,6 +2215,7 @@ extern std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE; extern std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE; extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE; +extern IData VL_FERROR_IW(IData fpi, int obits, WDataOutP outwp) VL_MT_SAFE; extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE; extern IData VL_FOPEN_MCD_N(const std::string& filename) VL_MT_SAFE; extern void VL_READMEM_N(bool hex, int bits, QData depth, int array_lsb, diff --git a/include/verilated_std.sv b/include/verilated_std.sv index a5c560920..1c7e60e0e 100644 --- a/include/verilated_std.sv +++ b/include/verilated_std.sv @@ -26,6 +26,10 @@ // verilator lint_off TIMESCALEMOD // verilator lint_off UNUSEDSIGNAL package std; + // The process class is not implemented, but it's predeclared here, + // so the linter accepts references to it. + typedef class process; + class mailbox #(type T); protected int m_bound; protected T m_queue[$]; @@ -112,6 +116,3 @@ package std; endfunction endclass endpackage - -// verilator lint_off IMPORTSTAR -import std::*; diff --git a/include/verilated_sym_props.h b/include/verilated_sym_props.h index f3167126c..bcf9c01a5 100644 --- a/include/verilated_sym_props.h +++ b/include/verilated_sym_props.h @@ -137,35 +137,35 @@ public: ~VerilatedVarProps() = default; // METHODS bool magicOk() const { return m_magic == MAGIC; } - VerilatedVarType vltype() const { return m_vltype; } + VerilatedVarType vltype() const VL_MT_SAFE { return m_vltype; } VerilatedVarFlags vldir() const { return static_cast(static_cast(m_vlflags) & VLVF_MASK_DIR); } - uint32_t entSize() const; + uint32_t entSize() const VL_MT_SAFE; bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); } // DPI compatible C standard layout bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); } - int udims() const { return m_udims; } + int udims() const VL_MT_SAFE { return m_udims; } int dims() const { return m_pdims + m_udims; } - const VerilatedRange& packed() const { return m_packed; } + const VerilatedRange& packed() const VL_MT_SAFE { return m_packed; } const VerilatedRange& unpacked() const { return m_unpacked[0]; } // DPI accessors - int left(int dim) const { + int left(int dim) const VL_MT_SAFE { return dim == 0 ? m_packed.left() : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left() : 0; } - int right(int dim) const { + int right(int dim) const VL_MT_SAFE { return dim == 0 ? m_packed.right() : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right() : 0; } - int low(int dim) const { + int low(int dim) const VL_MT_SAFE { return dim == 0 ? m_packed.low() : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low() : 0; } - int high(int dim) const { + int high(int dim) const VL_MT_SAFE { return dim == 0 ? m_packed.high() : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high() : 0; @@ -175,7 +175,7 @@ public: : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment() : 0; } - int elements(int dim) const { + int elements(int dim) const VL_MT_SAFE { return dim == 0 ? m_packed.elements() : VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements() : 0; @@ -183,7 +183,7 @@ public: // Total size in bytes (note DPI limited to 4GB) size_t totalSize() const; // Adjust a data pointer to access a given array element, NULL if something goes bad - void* datapAdjustIndex(void* datap, int dim, int indx) const; + void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE; }; //=========================================================================== @@ -203,22 +203,22 @@ public: , m_datap{const_cast(datap)} {} ~VerilatedDpiOpenVar() = default; // METHODS - void* datap() const { return m_datap; } + void* datap() const VL_MT_SAFE { return m_datap; } // METHODS - from VerilatedVarProps bool magicOk() const { return m_propsp->magicOk(); } VerilatedVarType vltype() const { return m_propsp->vltype(); } bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); } const VerilatedRange& packed() const { return m_propsp->packed(); } const VerilatedRange& unpacked() const { return m_propsp->unpacked(); } - int udims() const { return m_propsp->udims(); } - int left(int dim) const { return m_propsp->left(dim); } - int right(int dim) const { return m_propsp->right(dim); } + int udims() const VL_MT_SAFE { return m_propsp->udims(); } + int left(int dim) const VL_MT_SAFE { return m_propsp->left(dim); } + int right(int dim) const VL_MT_SAFE { return m_propsp->right(dim); } int low(int dim) const { return m_propsp->low(dim); } int high(int dim) const { return m_propsp->high(dim); } int increment(int dim) const { return m_propsp->increment(dim); } int elements(int dim) const { return m_propsp->elements(dim); } size_t totalSize() const { return m_propsp->totalSize(); } - void* datapAdjustIndex(void* datap, int dim, int indx) const { + void* datapAdjustIndex(void* datap, int dim, int indx) const VL_MT_SAFE { return m_propsp->datapAdjustIndex(datap, dim, indx); } }; diff --git a/include/verilated_types.h b/include/verilated_types.h index 1442f7d1d..cb7265e32 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -45,6 +45,7 @@ extern std::string VL_TO_STRING(CData lhs); extern std::string VL_TO_STRING(SData lhs); extern std::string VL_TO_STRING(IData lhs); extern std::string VL_TO_STRING(QData lhs); +extern std::string VL_TO_STRING(double lhs); inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; } extern std::string VL_TO_STRING_W(int words, const WDataInP obj); @@ -1168,7 +1169,9 @@ public: explicit VlClassRef(VlNull){}; template VlClassRef(VlDeleter& deleter, T_Args&&... args) - : m_objp{new T_Class{std::forward(args)...}} { + // () required here to avoid narrowing conversion warnings, + // when a new() has an e.g. CData type and passed a 1U. + : m_objp{new T_Class(std::forward(args)...)} { m_objp->m_deleterp = &deleter; refCountInc(); } diff --git a/include/verilatedos.h b/include/verilatedos.h index 0e30164a3..7efd61e21 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -519,6 +519,8 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read() # define VL_CPU_RELAX() asm volatile("nop" ::: "memory"); #elif defined(__aarch64__) || defined(__arm__) # define VL_CPU_RELAX() asm volatile("yield" ::: "memory") +#elif defined(__hppa__) // HPPA does not currently have yield/pause +# define VL_CPU_RELAX() asm volatile("nop" ::: "memory") #elif defined(__loongarch__) // LoongArch does not currently have yield/pause # define VL_CPU_RELAX() asm volatile("nop" ::: "memory") #elif defined(__mips64el__) || defined(__mips__) || defined(__mips64__) || defined(__mips64) diff --git a/install-sh b/install-sh index 058b26c82..15d507323 100644 --- a/install-sh +++ b/install-sh @@ -106,7 +106,7 @@ done if [ x"$src" = x ] then - echo "install: no input file specified" + echo "install: no input file specified" exit 1 else true @@ -137,7 +137,7 @@ else if [ x"$dst" = x ] then - echo "install: no destination specified" + echo "install: no destination specified" exit 1 else true diff --git a/nodist/clang_check_attributes b/nodist/clang_check_attributes index 825e50520..5c6aec2df 100755 --- a/nodist/clang_check_attributes +++ b/nodist/clang_check_attributes @@ -239,6 +239,7 @@ class CallAnnotationsValidator: self._call_location: Optional[FunctionInfo] = None self._caller: Optional[FunctionInfo] = None self._level: int = 0 + self._constructor_context: int = 0 def compile_and_analyze_file(self, source_file: str, compiler_args: list[str], @@ -300,6 +301,67 @@ class CallAnnotationsValidator: annotations = VlAnnotations.from_nodes_list(children) return (True, refd, annotations, children) + def check_mt_safe_call(self, node: clang.cindex.Cursor, + refd: clang.cindex.Cursor, + annotations: VlAnnotations): + is_mt_safe = False + + if annotations.is_mt_safe_call(): + is_mt_safe = True + elif not annotations.is_mt_unsafe_call(): + # Check whether the object the method is called on is mt-safe + def find_object_ref(node): + try: + node = next(node.get_children()) + if node.kind == CursorKind.DECL_REF_EXPR: + # Operator on an argument or local object + return node + if node.kind != CursorKind.MEMBER_REF_EXPR: + return None + if node.referenced and node.referenced.kind == CursorKind.FIELD_DECL: + # Operator on a member object + return node + node = next(node.get_children()) + if node.kind == CursorKind.UNEXPOSED_EXPR: + node = next(node.get_children()) + return node + except StopIteration: + return None + + refn = find_object_ref(node) + if self._constructor_context and not refn: + # we are in constructor and no object reference means + # we are calling local method. It is MT safe + # only if this method is also only calling local methods or + # MT-safe methods + self.iterate_children(refd.get_children(), + self.dispatch_node_inside_definition) + is_mt_safe = True + # class/struct member + elif refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced: + refn = refn.referenced + refna = VlAnnotations.from_nodes_list(refn.get_children()) + if refna.guarded or self._constructor_context: + is_mt_safe = True + # variable + elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced: + # This is probably a local or an argument. + # Calling methods on local pointers or references is MT-safe, + # but on argument pointers or references is not. + if "*" not in refn.type.spelling and "&" not in refn.type.spelling: + is_mt_safe = True + # local variable + if refn.referenced.kind == CursorKind.VAR_DECL: + is_mt_safe = True + elif refn and refn.kind == CursorKind.CALL_EXPR: + if self._constructor_context: + # call to local function from constructor context + # safe if this function also calling local methods or + # MT-safe methods + self.dispatch_call_node(refn) + is_mt_safe = True + return is_mt_safe + # Call handling def process_method_call(self, node: clang.cindex.Cursor, @@ -310,43 +372,7 @@ class CallAnnotationsValidator: # MT-safe context if ctx.is_mt_safe_context(): - is_mt_safe = False - - if annotations.is_mt_safe_call(): - is_mt_safe = True - elif not annotations.is_mt_unsafe_call(): - # Check whether the object the method is called on is mt-safe - def find_object_ref(node): - try: - node = next(node.get_children()) - if node.kind == CursorKind.DECL_REF_EXPR: - # Operator on an argument or local object - return node - if node.kind != CursorKind.MEMBER_REF_EXPR: - return None - if node.referenced and node.referenced.kind == CursorKind.FIELD_DECL: - # Operator on a member object - return node - node = next(node.get_children()) - if node.kind == CursorKind.UNEXPOSED_EXPR: - node = next(node.get_children()) - return node - except StopIteration: - return None - - refn = find_object_ref(node) - # class/struct member - if refn and refn.kind == CursorKind.MEMBER_REF_EXPR and refn.referenced: - refn = refn.referenced - refna = VlAnnotations.from_nodes_list(refn.get_children()) - if refna.guarded: - is_mt_safe = True - # variable - elif refn and refn.kind == CursorKind.DECL_REF_EXPR and refn.referenced: - # This is probably a local or an argument. Assume it's safe. - is_mt_safe = True - - if not is_mt_safe: + if not self.check_mt_safe_call(node, refd, annotations): self.emit_diagnostic( FunctionInfo.from_node(refd, refd, annotations), DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX) @@ -380,7 +406,13 @@ class CallAnnotationsValidator: assert self._call_location ctx = self._call_location.annotations - # Constructors are always OK in MT-safe context. + # Constructors are OK in MT-safe context + # only if they call local methods or MT-safe functions. + if ctx.is_mt_safe_context() or self._constructor_context: + self._constructor_context += 1 + self.iterate_children(refd.get_children(), + self.dispatch_node_inside_definition) + self._constructor_context -= 1 # pure context if ctx.is_pure_context(): @@ -412,6 +444,8 @@ class CallAnnotationsValidator: or refd.kind == CursorKind.CXX_METHOD and refd.is_static_method()): self.process_function_call(refd, annotations) + self.iterate_children(node.get_children(), + self.dispatch_node_inside_definition) return # Function pointer if refd.kind in [ @@ -419,18 +453,26 @@ class CallAnnotationsValidator: CursorKind.PARM_DECL ]: self.process_function_call(refd, annotations) + self.iterate_children(node.get_children(), + self.dispatch_node_inside_definition) return # Non-static class methods if refd.kind == CursorKind.CXX_METHOD: self.process_method_call(node, refd, annotations) + self.iterate_children(node.get_children(), + self.dispatch_node_inside_definition) return # Conversion method (e.g. `operator int()`) if refd.kind == CursorKind.CONVERSION_FUNCTION: self.process_method_call(node, refd, annotations) + self.iterate_children(node.get_children(), + self.dispatch_node_inside_definition) return # Constructors if refd.kind == CursorKind.CONSTRUCTOR: self.process_constructor_call(refd, annotations) + self.iterate_children(node.get_children(), + self.dispatch_node_inside_definition) return # Ignore other callables @@ -461,9 +503,6 @@ class CallAnnotationsValidator: assert refd is not None - prev_caller = self._caller - prev_call_location = self._call_location - def_annotations = VlAnnotations.from_nodes_list(node_children) if not (def_annotations.is_empty() or def_annotations == annotations): @@ -485,8 +524,7 @@ class CallAnnotationsValidator: self.iterate_children(node_children, self.dispatch_node_inside_definition) - self._call_location = prev_call_location - self._caller = prev_caller + self._call_location = None return None @@ -704,8 +742,7 @@ class TopDownSummaryPrinter(): info: FunctionInfo calees: set[FunctionInfo] mismatch: Optional[FunctionInfo] = None - non_mt_safe_call_in_mt_safe: Optional[FunctionInfo] = None - non_pure_call_in_pure: Optional[FunctionInfo] = None + reason: Optional[DiagnosticKind] = None def __init__(self): self._is_first_group = True @@ -727,15 +764,12 @@ class TopDownSummaryPrinter(): if func is None: func = TopDownSummaryPrinter.FunctionCallees(diag.source, set()) self._funcs[usr] = func + func.reason = diag.kind if diag.kind == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH: func.mismatch = diag.target else: func.calees.add(diag.target) self._unsafe_in_safe.add(diag.target.usr) - if diag.kind == DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX: - func.non_mt_safe_call_in_mt_safe = diag.target - elif diag.kind == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX: - func.non_pure_call_in_pure = diag.target def print_summary(self, root_dir: str): row_groups: dict[str, list[list[str]]] = {} @@ -748,11 +782,11 @@ class TopDownSummaryPrinter(): row_group = [] name = f"\"{func_info.name}\" " - if func.mismatch: + if func.reason == DiagnosticKind.ANNOTATIONS_DEF_DECL_MISMATCH: name += "declaration does not match definition" - elif func.non_mt_safe_call_in_mt_safe: + elif func.reason == DiagnosticKind.NON_MT_SAFE_CALL_IN_MT_SAFE_CTX: name += "is mtsafe but calls non-mtsafe function(s)" - elif func.non_pure_call_in_pure: + elif func.reason == DiagnosticKind.NON_PURE_CALL_IN_PURE_CTX: name += "is pure but calls non-pure function(s)" else: name += "for unknown reason (please add description)" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 54d979b8a..dc8dcf182 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -47,7 +47,6 @@ set(HEADERS V3Case.h V3Cast.h V3CCtors.h - V3Cdc.h V3Class.h V3Clean.h V3Clock.h @@ -150,6 +149,7 @@ set(HEADERS V3SymTable.h V3Table.h V3Task.h + V3ThreadPool.h V3Timing.h V3Trace.h V3TraceDecl.h @@ -186,7 +186,6 @@ set(COMMON_SOURCES V3CUse.cpp V3Case.cpp V3Cast.cpp - V3Cdc.cpp V3Class.cpp V3Clean.cpp V3Clock.cpp @@ -283,6 +282,7 @@ set(COMMON_SOURCES V3Subst.cpp V3Table.cpp V3Task.cpp + V3ThreadPool.cpp V3Trace.cpp V3TraceDecl.cpp V3Tristate.cpp diff --git a/src/Makefile.in b/src/Makefile.in index 15d34ebd6..c8e94fe50 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -50,7 +50,7 @@ obj_dbg: .PHONY: ../bin/verilator_bin$(EXEEXT) ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT) opt: ../bin/verilator_bin$(EXEEXT) -ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build +ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build ../bin/verilator_bin$(EXEEXT): ../bin/verilator_bin_dbg$(EXEEXT) -cp -p $< $@.tmp -mv -f $@.tmp $@ @@ -70,7 +70,7 @@ dbg: ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj ifneq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... don't rebuild each commit - ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users + ifneq ($(UNDER_GIT),) # If local git tree... else don't burden users GIT_CHANGE_DEP = ${srcdir}/../.git/logs/HEAD endif endif @@ -78,7 +78,7 @@ endif prefiles:: prefiles:: config_rev.h # This output goes into srcdir if locally configured, as we need to distribute it as part of the kit. -config_rev.h: ${srcdir}/config_rev $(GIT_CHANGE_DEP) +config_rev.h: ${srcdir}/config_rev $(GIT_CHANGE_DEP) $(PYTHON3) ${srcdir}/config_rev ${srcdir} >$@ # Human convenience diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index dd177da20..1db782e52 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -94,9 +94,9 @@ LIBS = $(CFG_LIBS) -lm CPPFLAGS += -MMD CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include -#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool +#CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool CPPFLAGS += -MP # Only works on recent GCC versions -ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users +ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users CPPFLAGS += -W -Wall $(CFG_CXXFLAGS_WEXTRA) $(CFG_CXXFLAGS_SRC) -Werror #CPPFLAGS += -pedantic-errors else @@ -114,7 +114,7 @@ ifeq ($(CFG_WITH_DEFENV),yes) CPPFLAGS += -DDEFENV_SYSTEMC_ARCH=\"$(SYSTEMC_ARCH)\" CPPFLAGS += -DDEFENV_SYSTEMC_INCLUDE=\"$(SYSTEMC_INCLUDE)\" CPPFLAGS += -DDEFENV_SYSTEMC_LIBDIR=\"$(SYSTEMC_LIBDIR)\" - ifeq ($(VERILATOR_ROOT),) # Use what we're given, or intuit + ifeq ($(VERILATOR_ROOT),) # Use what we're given, or intuit CPPFLAGS += -DDEFENV_VERILATOR_ROOT=\"$(pkgdatadir)\" else CPPFLAGS += -DDEFENV_VERILATOR_ROOT=\"$(VERILATOR_ROOT)\" @@ -155,7 +155,7 @@ RAW_OBJS = \ V3ActiveTop.o \ V3Assert.o \ V3AssertPre.o \ - V3Ast.o \ + V3Ast.o \ V3AstNodes.o \ V3Begin.o \ V3Branch.o \ @@ -164,7 +164,6 @@ RAW_OBJS = \ V3CUse.o \ V3Case.o \ V3Cast.o \ - V3Cdc.o \ V3Class.o \ V3Clean.o \ V3Clock.o \ @@ -265,6 +264,7 @@ RAW_OBJS = \ V3TSP.o \ V3Table.o \ V3Task.o \ + V3ThreadPool.o \ V3Timing.o \ V3Trace.o \ V3TraceDecl.o \ @@ -322,26 +322,26 @@ V3Number_test: V3Number_test.o #### Modules -%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS) +%__gen.cpp: %.cpp $(ASTGEN) $(AST_DEFS) $(DFG_DEFS) $(PYTHON3) $(ASTGEN) $(ASTGENFLAGS) $*.cpp .SECONDARY: -%.o: %.cpp +%.o: %.cpp $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSWALL} -c $< -o $@ -%.o: %.c +%.o: %.c $(OBJCACHE) ${CC} ${CFLAGS} ${CPPFLAGSWALL} -c $< -o $@ -V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c +V3ParseLex.o: V3ParseLex.cpp V3Lexer.yy.cpp V3ParseBison.c $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@ -V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c +V3ParseGrammar.o: V3ParseGrammar.cpp V3ParseBison.c $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@ -V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c +V3ParseImp.o: V3ParseImp.cpp V3ParseBison.c $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@ -V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp +V3PreProc.o: V3PreProc.cpp V3PreLex.yy.cpp $(OBJCACHE) ${CXX} ${CXXFLAGS} ${CPPFLAGSPARSER} -c $< -o $@ #### Generated files @@ -365,14 +365,14 @@ V3ParseBison.c: verilog.y $(BISONPRE) @echo "If you get errors from verilog.y below, try upgrading bison to version 1.875 or newer." $(PYTHON3) $(BISONPRE) --yacc ${YACC} -d -v -o V3ParseBison.c $< -V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS) +V3Lexer_pregen.yy.cpp: verilog.l V3ParseBison.h $(HEADERS) ${LEX} --version ${LEX} ${LFLAGS} -o$@ $< -V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX) +V3Lexer.yy.cpp: V3Lexer_pregen.yy.cpp $(FLEXFIX) $(PYTHON3) $(FLEXFIX) V3Lexer <$< >$@ -V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS) +V3PreLex_pregen.yy.cpp: V3PreLex.l $(HEADERS) ${LEX} --version ${LEX} ${LFLAGS} -o$@ $< diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 7b33bc841..ac8d96a42 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -43,6 +43,7 @@ private: AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable unsigned m_modPastNum = 0; // Module past numbering unsigned m_modStrobeNum = 0; // Module $strobe numbering + const AstNodeProcedure* m_procedurep = nullptr; // Current procedure VDouble0 m_statCover; // Statistic tracking VDouble0 m_statAsNotImm; // Statistic tracking VDouble0 m_statAsImm; // Statistic tracking @@ -145,6 +146,11 @@ private: } else { UASSERT_OBJ(sentreep, nodep, "Concurrent assertions must have sensitivity"); sentreep->unlinkFrBack(); + if (m_procedurep) { + // To support this need queue of asserts to activate + nodep->v3error("Unsupported: Procedural concurent assertion with" + " clocking event inside always (IEEE 1800-2917 16.14.6)"); + } } // AstNode* bodysp = nullptr; @@ -350,8 +356,7 @@ private: AstNodeExpr* const exprp = nodep->exprp()->unlinkFrBack(); AstNodeExpr* inp = newSampledExpr(exprp); AstVar* invarp = nullptr; - AstSenTree* const sentreep = nodep->sentreep(); - sentreep->unlinkFrBack(); + AstSenTree* const sentreep = nodep->sentreep()->unlinkFrBack(); AstAlways* const alwaysp = new AstAlways{nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr}; m_modp->addStmtsp(alwaysp); @@ -496,6 +501,11 @@ private: iterateChildren(nodep); } } + void visit(AstNodeProcedure* nodep) override { + VL_RESTORER(m_procedurep); + m_procedurep = nodep; + iterateChildren(nodep); + } void visit(AstBegin* nodep) override { // This code is needed rather than a visitor in V3Begin, // because V3Assert is called before V3Begin diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index b27a36c1b..8221ee0ab 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -63,9 +63,10 @@ private: // METHODS - AstSenTree* newSenTree(AstNode* nodep) { + AstSenTree* newSenTree(AstNode* nodep, AstSenTree* useTreep = nullptr) { // Create sentree based on clocked or default clock // Return nullptr for always + if (useTreep) return useTreep; AstSenTree* newp = nullptr; AstSenItem* senip = m_senip; if (!senip && m_defaultClockingp) senip = m_defaultClockingp->sensesp(); @@ -362,17 +363,19 @@ private: clearAssertInfo(); } void visit(AstFell* nodep) override { - if (nodep->sentreep()) return; // Already processed + if (nodep->user1SetOnce()) return; iterateChildren(nodep); FileLine* const fl = nodep->fileline(); AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack(); if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1}; + AstSenTree* sentreep = nodep->sentreep(); + if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTree(false)}}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); - nodep->sentreep(newSenTree(nodep)); + nodep->sentreep(newSenTree(nodep, sentreep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); } void visit(AstPast* nodep) override { @@ -381,30 +384,34 @@ private: nodep->sentreep(newSenTree(nodep)); } void visit(AstRose* nodep) override { - if (nodep->sentreep()) return; // Already processed + if (nodep->user1SetOnce()) return; iterateChildren(nodep); FileLine* const fl = nodep->fileline(); AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack(); if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1}; + AstSenTree* sentreep = nodep->sentreep(); + if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTree(false)}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); - nodep->sentreep(newSenTree(nodep)); + nodep->sentreep(newSenTree(nodep, sentreep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); } void visit(AstStable* nodep) override { - if (nodep->sentreep()) return; // Already processed + if (nodep->user1SetOnce()) return; iterateChildren(nodep); FileLine* const fl = nodep->fileline(); AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack(); + AstSenTree* sentreep = nodep->sentreep(); + if (sentreep) sentreep->unlinkFrBack(); AstNodeExpr* const past = new AstPast{fl, exprp, nullptr}; past->dtypeFrom(exprp); exprp = new AstEq{fl, past, exprp->cloneTree(false)}; exprp->dtypeSetBit(); nodep->replaceWith(exprp); - nodep->sentreep(newSenTree(nodep)); + nodep->sentreep(newSenTree(nodep, sentreep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); } diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index b77b329e4..db5722c64 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -87,8 +87,8 @@ string AstNode::encodeName(const string& namein) { // Encode signal name raw from parser, then not called again on same signal string out; for (string::const_iterator pos = namein.begin(); pos != namein.end(); ++pos) { - if ((pos == namein.begin()) ? isalpha(pos[0]) // digits can't lead identifiers - : isalnum(pos[0])) { + if ((pos == namein.begin()) ? std::isalpha(pos[0]) // digits can't lead identifiers + : std::isalnum(pos[0])) { out += pos[0]; } else if (pos[0] == '_') { if (pos[1] == '_') { @@ -158,7 +158,6 @@ string AstNode::vcdName(const string& namein) { string AstNode::prettyName(const string& namein) { // This function is somewhat hot, so we short-circuit some compares string pretty; - pretty = ""; pretty.reserve(namein.length()); for (const char* pos = namein.c_str(); *pos;) { if (pos[0] == '-' && pos[1] == '>') { // -> @@ -187,11 +186,14 @@ string AstNode::prettyName(const string& namein) { pos += 7; continue; } - if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && isxdigit(pos[3]) - && isxdigit(pos[4])) { + if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && std::isxdigit(pos[3]) + && std::isxdigit(pos[4])) { char value = 0; - value += 16 * (isdigit(pos[3]) ? (pos[3] - '0') : (tolower(pos[3]) - 'a' + 10)); - value += (isdigit(pos[4]) ? (pos[4] - '0') : (tolower(pos[4]) - 'a' + 10)); + value += 16 + * (std::isdigit(pos[3]) ? (pos[3] - '0') + : (std::tolower(pos[3]) - 'a' + 10)); + value + += (std::isdigit(pos[4]) ? (pos[4] - '0') : (std::tolower(pos[4]) - 'a' + 10)); pretty += value; pos += 5; continue; @@ -206,6 +208,81 @@ string AstNode::prettyName(const string& namein) { return pretty; } +string AstNode::vpiName(const string& namein) { + // This is slightly different from prettyName, in that when we encounter escaped characters, + // we change that identifier to an escaped identifier, wrapping it with '\' and ' ' + // as specified in LRM 23.6 + string pretty; + pretty.reserve(namein.length()); + bool inEscapedIdent = false; + int lastIdent = 0; + + for (const char* pos = namein.c_str(); *pos;) { + char specialChar = 0; + if (pos[0] == '-' && pos[1] == '>') { // -> + specialChar = '.'; + pos += 2; + } else if (pos[0] == '_' && pos[1] == '_') { // __ + if (0 == std::strncmp(pos, "__BRA__", 7)) { + specialChar = '['; + pos += 7; + } else if (0 == std::strncmp(pos, "__KET__", 7)) { + specialChar = ']'; + pos += 7; + } else if (0 == std::strncmp(pos, "__DOT__", 7)) { + specialChar = '.'; + pos += 7; + } else if (0 == std::strncmp(pos, "__PVT__", 7)) { + pos += 7; + continue; + } else if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && std::isxdigit(pos[3]) + && std::isxdigit(pos[4])) { + char value = 0; + value += 16 + * (std::isdigit(pos[3]) ? (pos[3] - '0') + : (std::tolower(pos[3]) - 'a' + 10)); + value + += (std::isdigit(pos[4]) ? (pos[4] - '0') : (std::tolower(pos[4]) - 'a' + 10)); + + // __ doesn't always imply escaped ident + if (value != '_') inEscapedIdent = true; + + pretty += value; + pos += 5; + continue; + } + } else if (pos[0] == '.') { + specialChar = '.'; + ++pos; + } + + if (specialChar) { + if (inEscapedIdent && (specialChar == '[' || specialChar == '.')) { + pretty += " "; + pretty.insert(lastIdent, "\\"); + inEscapedIdent = false; + } + + pretty += specialChar; + + if (specialChar == ']' || specialChar == '.') { + lastIdent = pretty.length(); + inEscapedIdent = false; + } + } else { + pretty += pos[0]; + ++pos; + } + } + if (inEscapedIdent) { + pretty += " "; + pretty.insert(lastIdent, "\\"); + } + if (pretty[0] == 'T' && pretty.substr(0, 4) == "TOP.") pretty.replace(0, 4, ""); + if (pretty[0] == 'T' && pretty.substr(0, 5) == "TOP->") pretty.replace(0, 5, ""); + return pretty; +} + string AstNode::prettyTypeName() const { if (name() == "") return typeName(); return std::string{typeName()} + " '" + prettyName() + "'"; @@ -1186,7 +1263,17 @@ void AstNode::dumpTreeDotFile(const string& filename, bool append, bool doDump) } } -void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_MT_SAFE { +bool AstNode::isTreePureRecurse() const { + // Should memoize this if call commonly + if (!this->isPure()) return false; + if (this->op1p() && !this->op1p()->isTreePureRecurse()) return false; + if (this->op2p() && !this->op2p()->isTreePureRecurse()) return false; + if (this->op3p() && !this->op3p()->isTreePureRecurse()) return false; + if (this->op4p() && !this->op4p()->isTreePureRecurse()) return false; + return true; +} + +void AstNode::v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { v3errorEnd(str); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; @@ -1216,9 +1303,9 @@ string AstNode::instanceStr() const { return ""; } -void AstNode::v3errorEnd(std::ostringstream& str) const { +void AstNode::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { if (!m_fileline) { - V3Error::v3errorEnd(str, instanceStr()); + V3Error::s().v3errorEnd(str, instanceStr()); } else { std::ostringstream nsstr; nsstr << str.str(); @@ -1231,8 +1318,8 @@ void AstNode::v3errorEnd(std::ostringstream& str) const { // Don't look for instance name when warning is disabled. // In case of large number of warnings, this can // take significant amount of time - m_fileline->v3errorEnd(nsstr, - m_fileline->warnIsOff(V3Error::errorCode()) ? "" : instanceStr()); + m_fileline->v3errorEnd( + nsstr, m_fileline->warnIsOff(V3Error::s().errorCode()) ? "" : instanceStr()); } } diff --git a/src/V3Ast.h b/src/V3Ast.h index f437f1ef9..eb7d345f7 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -371,7 +371,6 @@ public: // DT_PUBLIC, // V3LinkParse moves to AstTypedef::attrPublic // - ENUM_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes ENUM_FIRST, // V3Width processes ENUM_LAST, // V3Width processes ENUM_NUM, // V3Width processes @@ -380,8 +379,7 @@ public: ENUM_NAME, // V3Width processes ENUM_VALID, // V3Width processes // - MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes - // + TYPEID, // V3Width processes TYPENAME, // V3Width processes // VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes @@ -407,10 +405,9 @@ public: "DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT", "DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS", "DT_PUBLIC", - "ENUM_BASE", "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM", + "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM", "ENUM_NEXT", "ENUM_PREV", "ENUM_NAME", "ENUM_VALID", - "MEMBER_BASE", - "TYPENAME", + "TYPEID", "TYPENAME", "VAR_BASE", "VAR_CLOCK_ENABLE", "VAR_FORCEABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD", "VAR_PUBLIC_FLAT_RW", "VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT", "VAR_CLOCKER", @@ -570,7 +567,8 @@ public: } bool isIntNumeric() const { // Enum increment supported return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC - || m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64); + || m_e == LONGINT || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64 + || m_e == TIME); } bool isBitLogic() const { // Bit/logic vector types; can form a packed array return (m_e == LOGIC || m_e == BIT); @@ -805,6 +803,10 @@ public: bool isTemp() const { return (m_e == BLOCKTEMP || m_e == MODULETEMP || m_e == STMTTEMP || m_e == XTEMP); } + bool isVPIAccessible() const { + return (m_e == VAR || m_e == GPARAM || m_e == LPARAM || m_e == PORT || m_e == WIRE + || m_e == TRI0 || m_e == TRI1); + } }; constexpr bool operator==(const VVarType& lhs, const VVarType& rhs) VL_MT_SAFE { return lhs.m_e == rhs.m_e; @@ -1666,6 +1668,7 @@ public: string shortName() const; // Name with __PVT__ removed for concatenating scopes static string dedotName(const string& namein); // Name with dots removed static string prettyName(const string& namein); // Name for printing out to the user + static string vpiName(const string& namein); // Name for vpi access static string prettyNameQ(const string& namein) { // Quoted pretty name (for errors) return std::string{"'"} + prettyName(namein) + "'"; } @@ -1852,12 +1855,15 @@ public: static AstBasicDType* findInsertSameDType(AstBasicDType* nodep); // METHODS - dump and error - void v3errorEnd(std::ostringstream& str) const VL_MT_SAFE; - void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN VL_MT_SAFE; - string warnContextPrimary() const { return fileline()->warnContextPrimary(); } + void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex); + void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN + VL_REQUIRES(V3Error::s().m_mutex); + string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) { + return fileline()->warnContextPrimary(); + } string warnContextSecondary() const { return fileline()->warnContextSecondary(); } - string warnMore() const { return fileline()->warnMore(); } - string warnOther() const { return fileline()->warnOther(); } + string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); } + string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); } virtual void dump(std::ostream& str = std::cout) const; static void dumpGdb(const AstNode* nodep); // For GDB only @@ -1920,6 +1926,8 @@ public: void dumpTreeDot(std::ostream& os = std::cout) const; void dumpTreeDotFile(const string& filename, bool append = false, bool doDump = true); + bool isTreePureRecurse() const; + // METHODS - queries // Changes control flow, disable some optimizations virtual bool isBrancher() const { return false; } diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index a50a88006..fd652f595 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -60,6 +60,8 @@ public: /// are compound when methods calls operate on object, or when /// under another compound-requiring object e.g. class virtual bool isCompound() const = 0; + // Integral or packed, allowed inside an unpacked union/struct + virtual bool isIntegralOrPacked() const { return !isCompound(); } // (Slow) recurse down to find basic data type virtual AstBasicDType* basicp() const = 0; // recurses over typedefs/const/enum to next non-typeref type @@ -200,6 +202,7 @@ private: using MemberNameMap = std::map; // MEMBERS string m_name; // Name from upper typedef, if any + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy MemberNameMap m_members; const int m_uniqueNum; bool m_packed; @@ -255,6 +258,8 @@ public: static int lo() { return 0; } int hi() const { return dtypep()->width() - 1; } // Packed classes look like arrays VNumRange declRange() const { return VNumRange{hi(), lo()}; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; } }; // === Concrete node types ===================================================== @@ -470,6 +475,7 @@ public: VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; } void cvtRangeConst(); // Convert to smaller representation bool isCompound() const override { return isString(); } + bool isIntegralOrPacked() const override { return keyword().isIntNumeric(); } }; class AstBracketArrayDType final : public AstNodeDType { // Associative/Queue/Normal array data type, ie "[dtype_or_expr]" @@ -839,6 +845,7 @@ class AstMemberDType final : public AstNodeDType { // A member of a struct/union // PARENT: AstNodeUOrStructDType // @astgen op1 := childDTypep : Optional[AstNodeDType] + // @astgen op3 := valuep : Optional[AstNode] private: AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) string m_name; // Name of variable @@ -846,10 +853,12 @@ private: int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member // UNSUP: int m_randType; // Randomization type (IEEE) public: - AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) + AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp, + AstNode* valuep) : ASTGEN_SUPER_MemberDType(fl) , m_name{name} { childDTypep(dtp); // Only for parser + this->valuep(valuep); dtypep(nullptr); // V3Width will resolve refDTypep(nullptr); } @@ -862,6 +871,7 @@ public: widthFromSub(subDTypep()); } ASTGEN_MEMBERS_AstMemberDType; + void dumpSmall(std::ostream& str) const override; string name() const override { return m_name; } // * = Var name bool hasDType() const override { return true; } bool maybePointedTo() const override { return true; } @@ -1315,19 +1325,17 @@ public: std::vector unpackDimensions(); void isCompound(bool flag) { m_isCompound = flag; } bool isCompound() const override VL_MT_SAFE { return m_isCompound; } + bool isIntegralOrPacked() const override { return false; } }; // === AstNodeUOrStructDType === class AstStructDType final : public AstNodeUOrStructDType { - AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy public: // VSigning below is mispurposed to indicate if packed or not AstStructDType(FileLine* fl, VSigning numericUnpack) : ASTGEN_SUPER_StructDType(fl, numericUnpack) {} ASTGEN_MEMBERS_AstStructDType; string verilogKwd() const override { return "struct"; } - AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } - void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; } }; class AstUnionDType final : public AstNodeUOrStructDType { public: diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 243029f39..3ccc3a36f 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -249,6 +249,7 @@ public: void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } bool pli() const { return m_pli; } void pli(bool flag) { m_pli = flag; } + bool isPure() const override; string emitVerilog() final override { V3ERROR_NA_RETURN(""); } string emitC() final override { V3ERROR_NA_RETURN(""); } @@ -790,6 +791,51 @@ public: int instrCount() const override { return widthInstrs(); } bool same(const AstNode* /*samep*/) const override { return true; } }; +class AstConsPackMember final : public AstNodeExpr { + // Construct a packed array single emement [member1: value1] + // Don't need the member we are constructing, as the dtypep can get us to it + // @astgen op2 := rhsp : AstNodeExpr +public: + explicit AstConsPackMember(FileLine* fl, AstMemberDType* dtypep, AstNodeExpr* rhsp) + : ASTGEN_SUPER_ConsPackMember(fl) { + this->dtypep(dtypep); + this->rhsp(rhsp); + } + ASTGEN_MEMBERS_AstConsPackMember; + const char* broken() const override { + BROKEN_RTN(dtypep() && !VN_IS(dtypep(), MemberDType)); + return nullptr; + } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; +class AstConsPackUOrStruct final : public AstNodeExpr { + // Construct a packed struct and return object, '{member1: value1, member2: value2} + // Don't need the class we are constructing, as the dtypep can get us to it + // @astgen op1 := membersp : List[AstConsPackMember] +public: + explicit AstConsPackUOrStruct(FileLine* fl, AstNodeUOrStructDType* dtypep, + AstConsPackMember* membersp = nullptr) + : ASTGEN_SUPER_ConsPackUOrStruct(fl) { + this->dtypep(dtypep); + this->addMembersp(membersp); + } + ASTGEN_MEMBERS_AstConsPackUOrStruct; + const char* broken() const override { + BROKEN_RTN(dtypep() && !VN_IS(dtypep(), NodeUOrStructDType)); + return nullptr; + } + string emitVerilog() override { V3ERROR_NA_RETURN(""); } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { V3ERROR_NA_RETURN(""); } + bool cleanOut() const override { return true; } + int instrCount() const override { return widthInstrs(); } + bool same(const AstNode* /*samep*/) const override { return true; } +}; class AstConsQueue final : public AstNodeExpr { // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} // @astgen op1 := lhsp : Optional[AstNode] @@ -1183,9 +1229,10 @@ class AstFell final : public AstNodeExpr { // @astgen op1 := exprp : AstNodeExpr // @astgen op2 := sentreep : Optional[AstSenTree] public: - AstFell(FileLine* fl, AstNodeExpr* exprp) + AstFell(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep) : ASTGEN_SUPER_Fell(fl) { this->exprp(exprp); + this->sentreep(sentreep); } ASTGEN_MEMBERS_AstFell; string emitVerilog() override { return "$fell(%l)"; } @@ -1345,6 +1392,7 @@ public: const char* broken() const override; void dump(std::ostream& str) const override; string name() const override { return m_name; } + void name(const string& name) override { m_name = name; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return false; } @@ -1536,9 +1584,10 @@ class AstRose final : public AstNodeExpr { // @astgen op1 := exprp : AstNodeExpr // @astgen op2 := sentreep : Optional[AstSenTree] public: - AstRose(FileLine* fl, AstNodeExpr* exprp) + AstRose(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep) : ASTGEN_SUPER_Rose(fl) { this->exprp(exprp); + this->sentreep(sentreep); } ASTGEN_MEMBERS_AstRose; string emitVerilog() override { return "$rose(%l)"; } @@ -1754,9 +1803,10 @@ class AstStable final : public AstNodeExpr { // @astgen op1 := exprp : AstNodeExpr // @astgen op2 := sentreep : Optional[AstSenTree] public: - AstStable(FileLine* fl, AstNodeExpr* exprp) + AstStable(FileLine* fl, AstNodeExpr* exprp, AstSenTree* sentreep) : ASTGEN_SUPER_Stable(fl) { this->exprp(exprp); + this->sentreep(sentreep); } ASTGEN_MEMBERS_AstStable; string emitVerilog() override { return "$stable(%l)"; } @@ -1801,6 +1851,7 @@ public: } ASTGEN_MEMBERS_AstStructSel; string name() const override { return m_name; } + void name(const string& name) override { m_name = name; } string emitVerilog() override { V3ERROR_NA_RETURN(""); } string emitC() override { V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return false; } @@ -3304,6 +3355,30 @@ public: int instrCount() const override { return INSTR_COUNT_STR; } bool stringFlavor() const override { return true; } }; +class AstEqT final : public AstNodeBiCom { + // Equal (==) for data types +public: + AstEqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + : ASTGEN_SUPER_EqT(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_AstEqT; + AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override { + return new AstEqT{fileline(), lhsp, rhsp}; + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + string emitVerilog() override { return "%k(%l %f== %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "=="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } +}; class AstLogEq final : public AstNodeBiCom { public: AstLogEq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) @@ -3419,6 +3494,30 @@ public: int instrCount() const override { return INSTR_COUNT_STR; } bool stringFlavor() const override { return true; } }; +class AstNeqT final : public AstNodeBiCom { + // Not-equal (!=) for data types +public: + AstNeqT(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) + : ASTGEN_SUPER_NeqT(fl, lhsp, rhsp) { + dtypeSetBit(); + } + ASTGEN_MEMBERS_AstNeqT; + AstNodeExpr* cloneType(AstNodeExpr* lhsp, AstNodeExpr* rhsp) override { + return new AstNeqT{fileline(), lhsp, rhsp}; + } + void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { + V3ERROR_NA; + } + string emitVerilog() override { return "%k(%l %f!= %r)"; } + string emitC() override { V3ERROR_NA_RETURN(""); } + string emitSimpleOperator() override { return "!="; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return false; } + bool cleanRhs() const override { return false; } + bool sizeMattersLhs() const override { return false; } + bool sizeMattersRhs() const override { return false; } + int instrCount() const override { return INSTR_COUNT_STR; } +}; // === AstNodeBiComAsv === class AstAdd final : public AstNodeBiComAsv { @@ -4355,8 +4454,8 @@ public: case ATOOCT: return "atooct"; case ATOBIN: return "atobin"; case ATOREAL: return "atoreal"; - default: V3ERROR_NA; } + V3ERROR_NA_RETURN(""); } string emitVerilog() override { return "%l." + name() + "()"; } string emitC() override { @@ -4366,8 +4465,8 @@ public: case ATOOCT: return "VL_ATOI_N(%li, 8)"; case ATOBIN: return "VL_ATOI_N(%li, 2)"; case ATOREAL: return "std::atof(%li.c_str())"; - default: V3ERROR_NA; } + V3ERROR_NA_RETURN(""); } bool cleanOut() const override { return true; } bool cleanLhs() const override { return true; } @@ -4495,7 +4594,7 @@ public: dtypeSetString(); } ASTGEN_MEMBERS_AstCvtPackString; - void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAssign(lhs); } string emitVerilog() override { return "%f$_CAST(%l)"; } string emitC() override { return "VL_CVT_PACK_STR_N%lq(%lW, %li)"; } bool cleanOut() const override { return true; } @@ -4559,6 +4658,7 @@ public: bool cleanLhs() const override { return true; } bool sizeMattersLhs() const override { return false; } int instrCount() const override { return widthInstrs() * 16; } + bool isPredictOptimizable() const override { return false; } bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering AstNode* filep() const { return lhsp(); } }; @@ -4575,6 +4675,7 @@ public: bool cleanLhs() const override { return true; } bool sizeMattersLhs() const override { return false; } int instrCount() const override { return widthInstrs() * 64; } + bool isPredictOptimizable() const override { return false; } bool isPure() const override { return false; } // SPECIAL: $display has 'visual' ordering AstNode* filep() const { return lhsp(); } }; @@ -4674,6 +4775,21 @@ public: bool cleanLhs() const override { return true; } bool sizeMattersLhs() const override { return false; } }; +class AstNToI final : public AstNodeUniop { + // String to any-size integral +public: + AstNToI(FileLine* fl, AstNodeExpr* lhsp, AstNodeDType* dtypep = nullptr) + : ASTGEN_SUPER_NToI(fl, lhsp) { + this->dtypep(dtypep); + } + ASTGEN_MEMBERS_AstNToI; + void numberOperate(V3Number& out, const V3Number& lhs) override { out.opNToI(lhs); } + string emitVerilog() override { return "'(%l)"; } + string emitC() override { return "VL_NTOI_%nq(%nw, %P, %li)"; } + bool cleanOut() const override { return true; } + bool cleanLhs() const override { return true; } + bool sizeMattersLhs() const override { return false; } +}; class AstNegate final : public AstNodeUniop { public: AstNegate(FileLine* fl, AstNodeExpr* lhsp) diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index c71ccb688..87bad25ba 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -210,6 +210,7 @@ private: bool m_modTrace : 1; // Tracing this module bool m_inLibrary : 1; // From a library, no error if not used, never top level bool m_dead : 1; // LinkDot believes is dead; will remove in Dead visitors + bool m_hasGParam : 1; // Has global parameter (for link) bool m_hierBlock : 1; // Hierarchical Block marked by HIER_BLOCK pragma bool m_internal : 1; // Internally created bool m_recursive : 1; // Recursive module @@ -223,6 +224,7 @@ protected: , m_modTrace{false} , m_inLibrary{false} , m_dead{false} + , m_hasGParam{false} , m_hierBlock{false} , m_internal{false} , m_recursive{false} @@ -250,6 +252,8 @@ public: bool modTrace() const { return m_modTrace; } void dead(bool flag) { m_dead = flag; } bool dead() const { return m_dead; } + void hasGParam(bool flag) { m_hasGParam = flag; } + bool hasGParam() const { return m_hasGParam; } void hierBlock(bool flag) { m_hierBlock = flag; } bool hierBlock() const { return m_hierBlock; } void internal(bool flag) { m_internal = flag; } @@ -799,19 +803,24 @@ public: VTimescale timeunit() const { return m_timeunit; } }; class AstClassExtends final : public AstNode { + // class extends class name, or class implements class name // Children: List of AstParseRef for packages/classes // during early parse, then moves to dtype // @astgen op1 := childDTypep : Optional[AstNodeDType] // @astgen op2 := classOrPkgsp : Optional[AstNode] + const bool m_isImplements = false; // class implements public: - AstClassExtends(FileLine* fl, AstNode* classOrPkgsp) - : ASTGEN_SUPER_ClassExtends(fl) { + AstClassExtends(FileLine* fl, AstNode* classOrPkgsp, bool isImplements) + : ASTGEN_SUPER_ClassExtends(fl) + , m_isImplements{isImplements} { this->classOrPkgsp(classOrPkgsp); // Only for parser } ASTGEN_MEMBERS_AstClassExtends; + void dump(std::ostream& str) const override; bool hasDType() const override { return true; } - string verilogKwd() const override { return "extends"; } + string verilogKwd() const override { return isImplements() ? "implements" : "extends"; } AstClass* classp() const; // Class being extended (after link) + bool isImplements() const { return m_isImplements; } }; class AstClocking final : public AstNode { // Parents: MODULE @@ -822,19 +831,23 @@ class AstClocking final : public AstNode { // @astgen op4 := eventp : Optional[AstVar] std::string m_name; // Clocking block name const bool m_isDefault = false; // True if default clocking + const bool m_isGlobal = false; // True if global clocking public: AstClocking(FileLine* fl, const std::string& name, AstSenItem* sensesp, - AstClockingItem* itemsp, bool isDefault) + AstClockingItem* itemsp, bool isDefault, bool isGlobal) : ASTGEN_SUPER_Clocking(fl) - , m_isDefault{isDefault} { + , m_isDefault{isDefault} + , m_isGlobal{isGlobal} { m_name = name; this->sensesp(sensesp); addItemsp(itemsp); } ASTGEN_MEMBERS_AstClocking; + void dump(std::ostream& str) const override; std::string name() const override { return m_name; } bool isDefault() const { return m_isDefault; } + bool isGlobal() const { return m_isGlobal; } }; class AstClockingItem final : public AstNode { // Parents: CLOCKING @@ -1224,7 +1237,8 @@ private: AstVar* m_modVarp = nullptr; // Input/output this pin connects to on submodule. AstParamTypeDType* m_modPTypep = nullptr; // Param type this pin connects to on submodule. bool m_param = false; // Pin connects to parameter - bool m_svImplicit = false; // Pin is SystemVerilog .name'ed + bool m_svDotName = false; // Pin is SystemVerilog .name'ed + bool m_svImplicit = false; // Pin is SystemVerilog .name'ed, allow implicit public: AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) : ASTGEN_SUPER_Pin(fl) @@ -1248,6 +1262,8 @@ public: void modPTypep(AstParamTypeDType* nodep) { m_modPTypep = nodep; } bool param() const { return m_param; } void param(bool flag) { m_param = flag; } + bool svDotName() const { return m_svDotName; } + void svDotName(bool flag) { m_svDotName = flag; } bool svImplicit() const { return m_svImplicit; } void svImplicit(bool flag) { m_svImplicit = flag; } }; @@ -2090,14 +2106,15 @@ public: // === AstNodeModule === class AstClass final : public AstNodeModule { - // @astgen op4 := extendsp : Optional[AstClassExtends] + // @astgen op4 := extendsp : List[AstClassExtends] // TYPES using MemberNameMap = std::map; // MEMBERS MemberNameMap m_members; // Members or method children AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under - bool m_virtual = false; // Virtual class bool m_extended = false; // Is extension or extended by other classes + bool m_interfaceClass = false; // Interface class + bool m_virtual = false; // Virtual class void insertCache(AstNode* nodep); public: @@ -2125,6 +2142,8 @@ public: } bool isExtended() const { return m_extended; } void isExtended(bool flag) { m_extended = flag; } + bool isInterfaceClass() const { return m_interfaceClass; } + void isInterfaceClass(bool flag) { m_interfaceClass = flag; } bool isVirtual() const { return m_virtual; } void isVirtual(bool flag) { m_virtual = flag; } // Return true if this class is an extension of base class (SLOW) diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 7c69d1007..135674029 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -60,6 +60,12 @@ void AstNodeFTaskRef::cloneRelink() { } } +bool AstNodeFTaskRef::isPure() const { + // TODO: For non-DPI functions we could traverse the AST of function's body to determine + // pureness. + return this->taskp() && this->taskp()->dpiImport() && this->taskp()->pure(); +} + bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); } const char* AstNodeVarRef::broken() const { @@ -675,7 +681,7 @@ AstVar* AstVar::scVarRecurse(AstNode* nodep) { return nullptr; } -bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } +bool AstNodeDType::isFourstate() const { return basicp() && basicp()->isFourstate(); } class AstNodeDType::CTypeRecursed final { public: @@ -737,8 +743,8 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const { info.m_type = "VlUnpacked<" + sub.m_type; info.m_type += ", " + cvtToStr(adtypep->declRange().elements()); info.m_type += ">"; - } else if (VN_IS(dtypep, StructDType) && !VN_AS(dtypep, StructDType)->packed()) { - const auto* const sdtypep = VN_AS(dtypep, StructDType); + } else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) { + const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType); info.m_type = EmitCBaseVisitor::prefixNameProtect(sdtypep); } else if (const AstBasicDType* const bdtypep = dtypep->basicp()) { // We don't print msb()/lsb() as multidim packed would require recursion, @@ -869,7 +875,7 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep, bool overMembers) { continue; } // AstNodeSelPre stashes the associated variable under an ATTROF - // of VAttrType::VAR_BASE/MEMBER_BASE so it isn't constified + // of VAttrType::VAR_BASE so it isn't constified else if (VN_IS(nodep, AttrOf)) { nodep = VN_AS(nodep, AttrOf)->fromp(); continue; @@ -1458,6 +1464,7 @@ bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* ba void AstClass::dump(std::ostream& str) const { this->AstNodeModule::dump(str); if (isExtended()) str << " [EXT]"; + if (isInterfaceClass()) str << " [IFCCLS]"; if (isVirtual()) str << " [VIRT]"; } const char* AstClass::broken() const { @@ -1471,6 +1478,10 @@ void AstClass::cloneRelink() { m_classOrPackagep = m_classOrPackagep->clonep(); } } +void AstClassExtends::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (isImplements()) str << " [IMPLEMENTS]"; +} AstClass* AstClassExtends::classp() const { const AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType); if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.' @@ -1509,6 +1520,11 @@ void AstNodeCoverOrAssert::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); if (immediate()) str << " [IMMEDIATE]"; } +void AstClocking::dump(std::ostream& str) const { + this->AstNode::dump(str); + if (isDefault()) str << " [DEFAULT]"; + if (isGlobal()) str << " [GLOBAL]"; +} void AstDisplay::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); // str << " " << displayType().ascii(); @@ -1636,6 +1652,10 @@ void AstLogOr::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); if (sideEffect()) str << " [SIDE]"; } +void AstMemberDType::dumpSmall(std::ostream& str) const { + this->AstNodeDType::dumpSmall(str); + str << "member"; +} void AstMemberSel::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); str << " -> "; @@ -1704,6 +1724,7 @@ void AstPin::dump(std::ostream& str) const { } else { str << " ->UNLINKED"; } + if (svDotName()) str << " [.n]"; if (svImplicit()) str << " [.SV]"; } const char* AstPin::broken() const { diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 636b029e1..b936e33bb 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -19,6 +19,7 @@ // Look for BEGINs // BEGIN(VAR...) -> VAR ... {renamed} // FOR -> WHILEs +// Move static function variables and their AstInitialStatic blocks before a function // // There are two scopes; named BEGINs change %m and variable scopes. // Unnamed BEGINs change only variable, not $display("%m") scope. @@ -64,13 +65,14 @@ private: // STATE BeginState* const m_statep; // Current global state AstNodeModule* m_modp = nullptr; // Current module - const AstNodeFTask* m_ftaskp = nullptr; // Current function/task + AstNodeFTask* m_ftaskp = nullptr; // Current function/task AstNode* m_liftedp = nullptr; // Local nodes we are lifting into m_ftaskp string m_displayScope; // Name of %m in $display/AstScopeName string m_namedScope; // Name of begin blocks above us string m_unnamedScope; // Name of begin blocks, including unnamed blocks int m_ifDepth = 0; // Current if depth bool m_keepBegins = false; // True if begins should not be inlined + std::set m_staticFuncVars; // Static variables from m_ftaskp // METHODS @@ -121,6 +123,25 @@ private: } } + void renameAndStaticsRecurse(AstNode* const nodep) { + // Rename references and move InitialStatic items + if (AstVarRef* const varrefp = VN_CAST(nodep, VarRef)) { + const auto it = m_staticFuncVars.find(varrefp->varp()); + if (it != m_staticFuncVars.end()) varrefp->name((*it)->name()); + } + + if (nodep->op1p()) renameAndStaticsRecurse(nodep->op1p()); + if (nodep->op2p()) renameAndStaticsRecurse(nodep->op2p()); + if (nodep->op3p()) renameAndStaticsRecurse(nodep->op3p()); + if (nodep->op4p()) renameAndStaticsRecurse(nodep->op4p()); + if (nodep->nextp()) renameAndStaticsRecurse(nodep->nextp()); + + if (VN_IS(nodep, InitialStatic)) { + nodep->unlinkFrBack(); + m_ftaskp->addHereThisAsNext(nodep); + } + } + // VISITORS void visit(AstFork* nodep) override { // Keep this begin to group its statements together @@ -165,6 +186,7 @@ private: m_ftaskp = nodep; m_liftedp = nullptr; iterateChildren(nodep); + renameAndStaticsRecurse(nodep); if (m_liftedp) { // Place lifted nodes at beginning of stmtsp, so Var nodes appear before referenced if (AstNode* const stmtsp = nodep->stmtsp()) { @@ -174,6 +196,7 @@ private: nodep->addStmtsp(m_liftedp); m_liftedp = nullptr; } + m_staticFuncVars.clear(); m_ftaskp = nullptr; } } @@ -210,7 +233,15 @@ private: } } void visit(AstVar* nodep) override { - if (m_unnamedScope != "") { + // If static variable, move it outside a function. + if (nodep->lifetime().isStatic() && m_ftaskp) { + const std::string newName = m_ftaskp->name() + "__Vstatic__" + nodep->name(); + nodep->name(newName); + nodep->unlinkFrBack(); + m_ftaskp->addHereThisAsNext(nodep); + m_staticFuncVars.insert(nodep); + nodep->funcLocal(false); + } else if (m_unnamedScope != "") { // Rename it nodep->name(dot(m_unnamedScope, nodep->name())); m_statep->userMarkChanged(nodep); diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 76453af5f..c70e11b2a 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -155,6 +155,9 @@ private: V3CCtorsBuilder configure_coverage{nodep, "_configure_coverage", VCtorType::COVERAGE}; for (AstNode* np = nodep->stmtsp(); np; np = np->nextp()) { if (AstCoverDecl* const coverp = VN_CAST(np, CoverDecl)) { + // ... else we don't have a static VlSym to be able to coverage insert + UASSERT_OBJ(!VN_IS(nodep, Class), coverp, + "CoverDecl should be in class's package, not class itself"); np = coverp->backp(); configure_coverage.add(coverp->unlinkFrBack()); } diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 85a03b697..9085ba8d9 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -75,7 +75,7 @@ class CUseVisitor final : public VNVisitor { if (nodep->virtRefDType2p()) iterate(nodep->virtRefDType2p()); // Add a CUse for every struct that requires a declaration - AstStructDType* const stypep = VN_CAST(nodep->skipRefp(), StructDType); + AstNodeUOrStructDType* const stypep = VN_CAST(nodep->skipRefp(), NodeUOrStructDType); if (stypep && stypep->classOrPackagep()) { addNewUse(nodep, VUseType::INT_INCLUDE, stypep->classOrPackagep()->name()); iterateChildren(stypep); diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp deleted file mode 100644 index 0875bde87..000000000 --- a/src/V3Cdc.cpp +++ /dev/null @@ -1,765 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Clock Domain Crossing Lint -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// Copyright 2003-2023 by Wilson Snyder. This program is free software; you -// can redistribute it and/or modify it under the terms of either the GNU -// Lesser General Public License Version 3 or the Perl Artistic License -// Version 2.0. -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -// -//************************************************************************* -// V3Cdc's Transformations: -// -// Create V3Graph-ish graph -// Find all negedge reset flops -// Trace back to previous flop -// -//************************************************************************* - -#include "config_build.h" -#include "verilatedos.h" - -#include "V3Cdc.h" - -#include "V3Ast.h" -#include "V3Const.h" -#include "V3EmitV.h" -#include "V3File.h" -#include "V3Global.h" -#include "V3Graph.h" - -#include -#include -#include -#include - -VL_DEFINE_DEBUG_FUNCTIONS; - -constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async logic - -//###################################################################### - -class CdcBaseVisitor VL_NOT_FINAL : public VNVisitor { -public: -}; - -//###################################################################### -// Graph support classes - -class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex { - AstScope* const m_scopep; - AstNode* const m_nodep; - AstSenTree* m_srcDomainp = nullptr; - AstSenTree* m_dstDomainp = nullptr; - bool m_srcDomainSet : 1; - bool m_dstDomainSet : 1; - bool m_asyncPath : 1; - -public: - CdcEitherVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep) - : V3GraphVertex{graphp} - , m_scopep{scopep} - , m_nodep{nodep} - , m_srcDomainSet{false} - , m_dstDomainSet{false} - , m_asyncPath{false} {} - ~CdcEitherVertex() override = default; - // ACCESSORS - FileLine* fileline() const override { return nodep()->fileline(); } - AstScope* scopep() const { return m_scopep; } - AstNode* nodep() const { return m_nodep; } - AstSenTree* srcDomainp() const { return m_srcDomainp; } - void srcDomainp(AstSenTree* nodep) { m_srcDomainp = nodep; } - bool srcDomainSet() const { return m_srcDomainSet; } - void srcDomainSet(bool flag) { m_srcDomainSet = flag; } - AstSenTree* dstDomainp() const { return m_dstDomainp; } - void dstDomainp(AstSenTree* nodep) { m_dstDomainp = nodep; } - bool dstDomainSet() const { return m_dstDomainSet; } - void dstDomainSet(bool flag) { m_dstDomainSet = flag; } - bool asyncPath() const { return m_asyncPath; } - void asyncPath(bool flag) { m_asyncPath = flag; } -}; - -class CdcVarVertex final : public CdcEitherVertex { - AstVarScope* const m_varScp; - int m_cntAsyncRst = 0; - bool m_fromFlop = false; - -public: - CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) - : CdcEitherVertex{graphp, scopep, varScp} - , m_varScp{varScp} {} - ~CdcVarVertex() override = default; - // ACCESSORS - AstVarScope* varScp() const { return m_varScp; } - string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } - string dotColor() const override { - return fromFlop() ? "green" : cntAsyncRst() ? "red" : "blue"; - } - int cntAsyncRst() const { return m_cntAsyncRst; } - void cntAsyncRst(int flag) { m_cntAsyncRst = flag; } - bool fromFlop() const { return m_fromFlop; } - void fromFlop(bool flag) { m_fromFlop = flag; } -}; - -class CdcLogicVertex final : public CdcEitherVertex { - bool m_hazard : 1; - bool m_isFlop : 1; - -public: - CdcLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstSenTree* sensenodep) - : CdcEitherVertex{graphp, scopep, nodep} - , m_hazard{false} - , m_isFlop{false} { - srcDomainp(sensenodep); - dstDomainp(sensenodep); - } - ~CdcLogicVertex() override = default; - // ACCESSORS - string name() const override { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); } - string dotColor() const override { return hazard() ? "black" : "yellow"; } - bool hazard() const { return m_hazard; } - void setHazard(AstNode* nodep) { - m_hazard = true; - nodep->user3(true); - } - void clearHazard() { m_hazard = false; } - bool isFlop() const { return m_isFlop; } - void isFlop(bool flag) { m_isFlop = flag; } -}; - -//###################################################################### - -class CdcDumpVisitor final : public CdcBaseVisitor { -private: - // NODE STATE - // Entire netlist: - // {statement}Node::user3 -> bool, indicating not hazard - std::ofstream* const m_ofp = nullptr; // Output file - string m_prefix; - - void visit(AstNode* nodep) override { - *m_ofp << m_prefix; - if (nodep->user3()) { - *m_ofp << " %%"; - } else { - *m_ofp << " "; - } - *m_ofp << nodep->prettyTypeName() << "\n"; - const string lastPrefix = m_prefix; - m_prefix = lastPrefix + "1:"; - iterateAndNextNull(nodep->op1p()); - m_prefix = lastPrefix + "2:"; - iterateAndNextNull(nodep->op2p()); - m_prefix = lastPrefix + "3:"; - iterateAndNextNull(nodep->op3p()); - m_prefix = lastPrefix + "4:"; - iterateAndNextNull(nodep->op4p()); - m_prefix = lastPrefix; - } - -public: - // CONSTRUCTORS - CdcDumpVisitor(AstNode* nodep, std::ofstream* ofp, const string& prefix) - : m_ofp{ofp} - , m_prefix{prefix} { - iterate(nodep); - } - ~CdcDumpVisitor() override = default; -}; - -//###################################################################### - -class CdcWidthVisitor final : public CdcBaseVisitor { -private: - size_t m_maxFilenameLen = 0; - int m_maxLineno = 0; - - void visit(AstNode* nodep) override { - iterateChildren(nodep); - // Keeping line+filename lengths separate is much faster than calling ascii().length() - if (nodep->fileline()->lineno() >= m_maxLineno) { - m_maxLineno = nodep->fileline()->lineno() + 1; - } - if (nodep->fileline()->filename().length() >= m_maxFilenameLen) { - m_maxFilenameLen = nodep->fileline()->filename().length() + 1; - } - } - -public: - // CONSTRUCTORS - explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); } - ~CdcWidthVisitor() override = default; - // ACCESSORS - int maxWidth() const { - size_t width = 1; - width += m_maxFilenameLen; - width += 1; // The : - width += cvtToStr(m_maxLineno).length(); - width += 1; // Final : - return static_cast(width); - } -}; - -//###################################################################### -// Cdc class functions - -class CdcVisitor final : public CdcBaseVisitor { -private: - // NODE STATE - // Entire netlist: - // AstVarScope::user1p -> CdcVarVertex* for usage var, 0=not set yet - // AstVarScope::user2 -> bool Used in sensitivity list - // {statement}Node::user1p -> CdcLogicVertex* for this statement - // AstNode::user3 -> bool True indicates to print %% (via V3EmitV) - const VNUser1InUse m_inuser1; - const VNUser2InUse m_inuser2; - const VNUser3InUse m_inuser3; - - // STATE - V3Graph m_graph; // Scoreboard of var usages/dependencies - CdcLogicVertex* m_logicVertexp = nullptr; // Current statement being tracked, nullptr=ignored - AstScope* m_scopep = nullptr; // Current scope being processed - const AstNodeModule* m_modp = nullptr; // Current module - AstSenTree* m_domainp = nullptr; // Current sentree - bool m_inDly = false; // In delayed assign - int m_inSenItem = 0; // Number of senitems - string m_ofFilename; // Output filename - std::ofstream* m_ofp; // Output file - uint32_t m_userGeneration = 0; // Generation count to avoid slow userClearVertices - int m_filelineWidth = 0; // Characters in longest fileline - - // METHODS - void iterateNewStmt(AstNode* nodep) { - if (m_scopep) { - VL_RESTORER(m_logicVertexp); - UINFO(4, " STMT " << nodep << endl); - m_logicVertexp = new CdcLogicVertex{&m_graph, m_scopep, nodep, m_domainp}; - if (m_domainp && m_domainp->hasClocked()) { // To/from a flop - m_logicVertexp->isFlop(true); - m_logicVertexp->srcDomainp(m_domainp); - m_logicVertexp->srcDomainSet(true); - m_logicVertexp->dstDomainp(m_domainp); - m_logicVertexp->dstDomainSet(true); - } - iterateChildren(nodep); - - if (false && debug() >= 9) { - UINFO(9, "Trace Logic:\n"); - nodep->dumpTree("- log1: "); - } - } - } - - CdcVarVertex* makeVarVertex(AstVarScope* varscp) { - CdcVarVertex* vertexp = reinterpret_cast(varscp->user1p()); - if (!vertexp) { - UINFO(6, "New vertex " << varscp << endl); - vertexp = new CdcVarVertex{&m_graph, m_scopep, varscp}; - varscp->user1p(vertexp); - if (varscp->varp()->isUsedClock()) {} - if (varscp->varp()->isPrimaryIO()) { - // Create IO vertex - note it's relative to the pointed to var, not where we are - // now This allows reporting to easily print the input statement - CdcLogicVertex* const ioVertexp - = new CdcLogicVertex{&m_graph, varscp->scopep(), varscp->varp(), nullptr}; - if (varscp->varp()->isWritable()) { - new V3GraphEdge{&m_graph, vertexp, ioVertexp, 1}; - } else { - new V3GraphEdge{&m_graph, ioVertexp, vertexp, 1}; - } - } - } - if (m_inSenItem) { - varscp->user2(true); // It's like a clock... - // TODO: In the future mark it here and do normal clock tree glitch checks also - } else if (varscp->user2()) { // It was detected in a sensitivity list earlier - // And now it's used as logic. So must be a reset. - vertexp->cntAsyncRst(vertexp->cntAsyncRst() + 1); - } - return vertexp; - } - - void warnAndFile(AstNode* nodep, V3ErrorCode code, const string& msg) { - static bool told_file = false; - nodep->v3warnCode(code, msg); - if (!told_file) { - told_file = true; - std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl; - } - *m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << '\n'; - } - - void setNodeHazard(AstNode* nodep) { - // Need to not clear if warnings are off (rather than when report it) - // as bypassing this warning may turn up another path that isn't warning off'ed. - // We can't modifyWarnOff here, as one instantiation might not be - // an issue until we find a hitting flop. - // Furthermore, a module like a "Or" module would only get flagged - // once, even though the signals feeding it are radically different. - if (!m_domainp || m_domainp->hasCombo()) { - // Source flop logic in a posedge block is OK for reset (not async though) - if (m_logicVertexp && !nodep->fileline()->warnIsOff(V3ErrorCode::CDCRSTLOGIC)) { - UINFO(8, "Set hazard " << nodep << endl); - m_logicVertexp->setHazard(nodep); - } - } - } - - static string spaces(int level) { - string out; - while (level--) out += " "; - return out; - } // LCOV_EXCL_LINE - static string pad(unsigned column, const string& in) { - string out = in; - while (out.length() < column) out += ' '; - return out; - } - - void analyze() { - UINFO(3, __FUNCTION__ << ": " << endl); - if (dumpGraph() > 6) m_graph.dumpDotFilePrefixed("cdc_pre"); - // This will MAX across edge weights - m_graph.removeRedundantEdges(&V3GraphEdge::followAlwaysTrue); - // - if (dumpGraph() >= 3) m_graph.dumpDotFilePrefixed("cdc_simp"); - // - analyzeReset(); - } - - int filelineWidth() { - if (!m_filelineWidth) { - const CdcWidthVisitor visitor{v3Global.rootp()}; - m_filelineWidth = visitor.maxWidth(); - } - return m_filelineWidth; - } - - //---------------------------------------- - // RESET REPORT - - void analyzeReset() { - // Find all async reset wires, and trace backwards - // userClearVertices is very slow, so we use a generation count instead - m_graph.userClearVertices(); // user1: uint32_t - was analyzed generation - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (CdcVarVertex* const vvertexp = dynamic_cast(itp)) { - if (vvertexp->cntAsyncRst()) { - m_userGeneration++; // Effectively a userClearVertices() - UINFO(8, " Trace One async: " << vvertexp << endl); - // Twice, as we need to detect, then propagate - CdcEitherVertex* const markp = traceAsyncRecurse(vvertexp, false); - if (markp) { // Mark is non-nullptr if something bad on this path - UINFO(9, " Trace One bad! " << vvertexp << endl); - m_userGeneration++; // Effectively a userClearVertices() - traceAsyncRecurse(vvertexp, true); - m_userGeneration++; // Effectively a userClearVertices() - dumpAsync(vvertexp, markp); - } - } - } - } - } - - CdcEitherVertex* traceAsyncRecurse(CdcEitherVertex* vertexp, bool mark) { - // First pass: Return vertex of any hazardous stuff attached, or nullptr if OK - // If first pass returns true, second pass calls asyncPath() on appropriate nodes - if (vertexp->user() >= m_userGeneration) return nullptr; // Processed - prevent loop - vertexp->user(m_userGeneration); - - CdcEitherVertex* mark_outp = nullptr; - UINFO(9, " Trace: " << vertexp << endl); - - // Clear out in prep for marking next path - if (!mark) vertexp->asyncPath(false); - - if (CdcLogicVertex* const vvertexp = dynamic_cast(vertexp)) { - // Any logic considered bad, at the moment, anyhow - if (vvertexp->hazard() && !mark_outp) mark_outp = vvertexp; - // And keep tracing back so the user can understand what's up - } else if (CdcVarVertex* const vvertexp = dynamic_cast(vertexp)) { - if (mark) vvertexp->asyncPath(true); - // If primary I/O, it's ok here back - if (vvertexp->varScp()->varp()->isPrimaryInish()) { - // Show the source "input" statement if it exists - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - CdcEitherVertex* const eFromVertexp - = static_cast(edgep->fromp()); - eFromVertexp->asyncPath(true); - } - return nullptr; - } - // Also ok if from flop, but partially trace the flop so more obvious to users - if (vvertexp->fromFlop()) { - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - CdcEitherVertex* const eFromVertexp - = static_cast(edgep->fromp()); - eFromVertexp->asyncPath(true); - } - return nullptr; - } - } - - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - CdcEitherVertex* const eFromVertexp = static_cast(edgep->fromp()); - CdcEitherVertex* const submarkp = traceAsyncRecurse(eFromVertexp, mark); - if (submarkp && !mark_outp) mark_outp = submarkp; - } - - if (mark) vertexp->asyncPath(true); - return mark_outp; - } - - void dumpAsync(CdcVarVertex* vertexp, CdcEitherVertex* markp) { - const AstNode* const nodep = vertexp->varScp(); - *m_ofp << "\n"; - *m_ofp << "\n"; - CdcEitherVertex* targetp = vertexp; // One example destination flop (of possibly many) - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { - CdcEitherVertex* const eToVertexp = static_cast(edgep->top()); - if (!eToVertexp) targetp = eToVertexp; - if (const CdcLogicVertex* const vvertexp = dynamic_cast(eToVertexp)) { - if (vvertexp->isFlop() // IE the target flop that is upsetting us - && edgep->weight() >= CDC_WEIGHT_ASYNC) { // And var feeds an async reset line - targetp = eToVertexp; - // UINFO(9," targetasync "<name()<<" "<<" from - // "<name()<name()<<" "<nodep()->fileline()<nodep(), V3ErrorCode::CDCRSTLOGIC, - "Logic in path that feeds async reset, via signal: " + nodep->prettyNameQ()); - dumpAsyncRecurse(targetp, "", " ", 0); - } - bool dumpAsyncRecurse(CdcEitherVertex* vertexp, const string& prefix, const string& sep, - int level) { - // level=0 is special, indicates to dump destination flop - // Return true if printed anything - // If mark, also mark the output even if nothing hazardous below - if (vertexp->user() >= m_userGeneration) return false; // Processed - prevent loop - vertexp->user(m_userGeneration); - if (!vertexp->asyncPath() && level != 0) return false; // Not part of path - - // Other logic in the path - const string cont = prefix + sep; - string nextsep = " "; - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - CdcEitherVertex* const eFromVertexp = static_cast(edgep->fromp()); - if (dumpAsyncRecurse(eFromVertexp, cont, nextsep, level + 1)) nextsep = " | "; - } - - // Dump single variable/logic block - // See also OrderGraph::loopsVertexCb(V3GraphVertex* vertexp) - AstNode* const nodep = vertexp->nodep(); - const string front - = pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- "; - if (VN_IS(nodep, VarScope)) { - *m_ofp << front << "Variable: " << nodep->prettyName() << '\n'; - } else { - V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(), - vertexp->srcDomainp(), true); - if (debug()) { CdcDumpVisitor{nodep, m_ofp, front + "DBG: "}; } - } - - nextsep = " | "; - if (level) - *m_ofp << V3OutFile::indentSpaces(filelineWidth()) << " " << prefix << nextsep << "\n"; - - if (CdcLogicVertex* const vvertexp = dynamic_cast(vertexp)) { - // Now that we've printed a path with this hazard, don't bother to print any more - // Otherwise, we'd get a path for almost every destination flop - vvertexp->clearHazard(); - } - return true; - } - - //---------------------------------------- - // EDGE REPORTS - - void edgeReport() { - // Make report of all signal names and what clock edges they have - // - // Due to flattening, many interesting direct-connect signals are - // lost, so we can't make a report showing I/Os for a low level - // module. Disabling flattening though makes us consider each - // signal in it's own unique clock domain. - - UINFO(3, __FUNCTION__ << ": " << endl); - - // Trace all sources and sinks - for (const bool& traceDests : {false, true}) { - UINFO(9, " Trace Direction " << (traceDests ? "dst" : "src") << endl); - m_graph.userClearVertices(); // user1: bool - was analyzed - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (CdcVarVertex* const vvertexp = dynamic_cast(itp)) { - UINFO(9, " Trace One edge: " << vvertexp << endl); - edgeDomainRecurse(vvertexp, traceDests, 0); - } - } - } - - const string filename - = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt"; - const std::unique_ptr ofp{V3File::new_ofstream(filename)}; - if (ofp->fail()) v3fatal("Can't write " << filename); - *ofp << "Edge Report for " << v3Global.opt.prefix() << '\n'; - - std::deque report; // Sort output by name - for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { - if (const CdcVarVertex* const vvertexp = dynamic_cast(itp)) { - const AstVar* const varp = vvertexp->varScp()->varp(); - { - string what = "wire"; - if (varp->isPrimaryIO()) what = varp->direction().prettyName(); - - std::ostringstream os; - os.setf(std::ios::left); - // Module name - doesn't work due to flattening having lost the original - // so we assume the modulename matches the filebasename - const string fname = vvertexp->varScp()->fileline()->filebasename() + ":"; - os << " " << std::setw(20) << fname; - os << " " << std::setw(8) << what; - os << " " << std::setw(40) << vvertexp->varScp()->prettyName(); - os << " SRC="; - if (vvertexp->srcDomainp()) { - V3EmitV::verilogForTree(vvertexp->srcDomainp(), os); - } - os << " DST="; - if (vvertexp->dstDomainp()) { - V3EmitV::verilogForTree(vvertexp->dstDomainp(), os); - } - os << std::setw(0); - os << '\n'; - report.push_back(os.str()); - } - } - } - stable_sort(report.begin(), report.end()); - for (const auto& line : report) *ofp << line; - } - - void edgeDomainRecurse(CdcEitherVertex* vertexp, bool traceDests, int level) { - // Scan back to inputs/outputs, flops, and compute clock domain information - UINFO(8, spaces(level) << " Tracein " << vertexp << endl); - if (vertexp->user() >= m_userGeneration) return; // Mid-Processed - prevent loop - vertexp->user(m_userGeneration); - - // Variables from flops already are domained - if (traceDests ? vertexp->dstDomainSet() : vertexp->srcDomainSet()) { - return; - } // Fully computed - - std::set senouts; // List of all sensitivities for new signal - if (dynamic_cast(vertexp)) { - } else if (const CdcVarVertex* const vvertexp = dynamic_cast(vertexp)) { - // If primary I/O, give it domain of the input - const AstVar* const varp = vvertexp->varScp()->varp(); - if (varp->isPrimaryIO() && varp->isNonOutput() && !traceDests) { - senouts.insert(new AstSenTree{ - varp->fileline(), new AstSenItem{varp->fileline(), AstSenItem::Combo{}}}); - } - } - - // Now combine domains of sources/dests - if (traceDests) { - for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep; edgep = edgep->outNextp()) { - CdcEitherVertex* const eToVertexp = static_cast(edgep->top()); - edgeDomainRecurse(eToVertexp, traceDests, level + 1); - if (eToVertexp->dstDomainp()) senouts.insert(eToVertexp->dstDomainp()); - } - } else { - for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { - CdcEitherVertex* const eFromVertexp - = static_cast(edgep->fromp()); - edgeDomainRecurse(eFromVertexp, traceDests, level + 1); - if (eFromVertexp->srcDomainp()) senouts.insert(eFromVertexp->srcDomainp()); - } - } - - // Convert list of senses into one sense node - AstSenTree* senoutp = nullptr; - bool senedited = false; - for (const auto& itr : senouts) { - if (!senoutp) { - senoutp = itr; - } else { - if (!senedited) { - senedited = true; - senoutp = senoutp->cloneTree(true); - } - senoutp->addSensesp(itr->sensesp()->cloneTree(true)); - } - } - // If multiple domains need to do complicated optimizations - if (senedited) senoutp = VN_AS(V3Const::constifyExpensiveEdit(senoutp), SenTree); - if (traceDests) { - vertexp->dstDomainSet(true); // Note it's set - domainp may be null, so can't use that - vertexp->dstDomainp(senoutp); - if (debug() >= 9) { - UINFO(9, spaces(level) + " Tracedst " << vertexp); - if (senoutp) { - V3EmitV::verilogForTree(senoutp, cout); - cout << endl; - } - } - } else { - vertexp->srcDomainSet(true); // Note it's set - domainp may be null, so can't use that - vertexp->srcDomainp(senoutp); - if (debug() >= 9) { - UINFO(9, spaces(level) + " Tracesrc " << vertexp); - if (senoutp) { - V3EmitV::verilogForTree(senoutp, cout); - cout << endl; - } - } - } - } - - // VISITORS - void visit(AstNodeModule* nodep) override { - VL_RESTORER(m_modp); - { - m_modp = nodep; - iterateChildren(nodep); - } - } - void visit(AstScope* nodep) override { - UINFO(4, " SCOPE " << nodep << endl); - m_scopep = nodep; - m_logicVertexp = nullptr; - iterateChildren(nodep); - m_scopep = nullptr; - } - void visit(AstActive* nodep) override { - // Create required blocks and add to module - UINFO(4, " BLOCK " << nodep << endl); - AstNode::user2ClearTree(); - m_domainp = nodep->sensesp(); - // Ignore static initializers, initial and final blocks - if (!m_domainp || m_domainp->hasCombo() || m_domainp->hasClocked()) { - iterateNewStmt(nodep); - } - m_domainp = nullptr; - AstNode::user2ClearTree(); - } - void visit(AstNodeVarRef* nodep) override { - if (m_scopep) { - UASSERT_OBJ(m_logicVertexp, nodep, "Var ref not under a logic block"); - AstVarScope* const varscp = nodep->varScopep(); - UASSERT_OBJ(varscp, nodep, "Var didn't get varscoped in V3Scope.cpp"); - CdcVarVertex* const varvertexp = makeVarVertex(varscp); - UINFO(5, " VARREF to " << varscp << endl); - // We use weight of one for normal edges, - // Weight of CDC_WEIGHT_ASYNC to indicate feeds async (for reporting) - // When simplify we'll take the MAX weight - if (nodep->access().isWriteOrRW()) { - new V3GraphEdge{&m_graph, m_logicVertexp, varvertexp, 1}; - if (m_inDly) { - varvertexp->fromFlop(true); - varvertexp->srcDomainp(m_domainp); - varvertexp->srcDomainSet(true); - } - } else { - if (varvertexp->cntAsyncRst()) { - // UINFO(9," edgeasync "<name()<<" to "<name()<<" to "<lsbp(), Const)) setNodeHazard(nodep); - iterateChildren(nodep); - } - void visit(AstNodeSel* nodep) override { - if (!VN_IS(nodep->bitp(), Const)) setNodeHazard(nodep); - iterateChildren(nodep); - } - - // Ignores - void visit(AstInitial*) override {} - void visit(AstInitialAutomatic*) override {} - void visit(AstInitialStatic*) override {} - void visit(AstTraceDecl*) override {} - void visit(AstCoverToggle*) override {} - void visit(AstNodeDType*) override {} - - //-------------------- - // Default - void visit(AstNodeExpr* nodep) override { - setNodeHazard(nodep); - iterateChildren(nodep); - } - void visit(AstNode* nodep) override { iterateChildren(nodep); } - -public: - // CONSTRUCTORS - explicit CdcVisitor(AstNode* nodep) { - // Make report of all signal names and what clock edges they have - const string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc.txt"; - m_ofp = V3File::new_ofstream(filename); - if (m_ofp->fail()) v3fatal("Can't write " << filename); - m_ofFilename = filename; - *m_ofp << "CDC Report for " << v3Global.opt.prefix() << '\n'; - *m_ofp - << "Each dump below traces logic from inputs/source flops to destination flop(s).\n"; - *m_ofp << "First source logic is listed, then a variable that logic generates,\n"; - *m_ofp << "repeating recursively forwards to the destination flop(s).\n"; - *m_ofp << "%% Indicates the operator considered potentially hazardous.\n"; - - iterate(nodep); - analyze(); - if (debug() >= 1) edgeReport(); // Not useful to users at the moment - if (false) { - *m_ofp << "\nDBG-test-dumper\n"; - V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, nullptr, true); - *m_ofp << '\n'; - } - } - ~CdcVisitor() override { - if (m_ofp) VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); - } -}; - -//###################################################################### -// Cdc class functions - -void V3Cdc::cdcAll(AstNetlist* nodep) { - UINFO(2, __FUNCTION__ << ": " << endl); - { CdcVisitor{nodep}; } -} diff --git a/src/V3Cdc.h b/src/V3Cdc.h deleted file mode 100644 index d065cbd25..000000000 --- a/src/V3Cdc.h +++ /dev/null @@ -1,32 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Break always into sensitivity block domains -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// Copyright 2003-2023 by Wilson Snyder. This program is free software; you -// can redistribute it and/or modify it under the terms of either the GNU -// Lesser General Public License Version 3 or the Perl Artistic License -// Version 2.0. -// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -// -//************************************************************************* - -#ifndef VERILATOR_V3CDC_H_ -#define VERILATOR_V3CDC_H_ - -#include "config_build.h" -#include "verilatedos.h" - -class AstNetlist; - -//============================================================================ - -class V3Cdc final { -public: - static void cdcAll(AstNetlist* nodep); -}; - -#endif // Guard diff --git a/src/V3Class.cpp b/src/V3Class.cpp index f5e65b2a0..61513782a 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -156,6 +156,11 @@ private: // m_toScopeMoves.push_back(std::make_pair(nodep, m_classScopep)); //} } + void visit(AstCoverDecl* nodep) override { + // Need to declare coverage in package, where we have access to symbol table + iterateChildren(nodep); + if (m_classPackagep) m_classPackagep->addStmtsp(nodep->unlinkFrBack()); + } void visit(AstInitial* nodep) override { // But not AstInitialAutomatic, which remains under the class iterateChildren(nodep); @@ -171,24 +176,25 @@ private: } } - void setStructModulep(AstStructDType* const dtypep) { + void setStructModulep(AstNodeUOrStructDType* const dtypep) { // Give it a pointer to its package and a final name dtypep->classOrPackagep(m_modp); - dtypep->name(dtypep->name() + "__struct" + cvtToStr(dtypep->uniqueNum())); + dtypep->name(dtypep->name() + (VN_IS(dtypep, UnionDType) ? "__union" : "__struct") + + cvtToStr(dtypep->uniqueNum())); for (const AstMemberDType* itemp = dtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { - AstStructDType* const subp = VN_CAST(itemp->skipRefp(), StructDType); + AstNodeUOrStructDType* const subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType); // Recurse only into anonymous unpacked structs inside this definition, // other unpacked structs will be reached from another typedefs - if (subp && !subp->packed() && subp->name().empty()) { setStructModulep(subp); } + if (subp && !subp->packed() && subp->name().empty()) setStructModulep(subp); } } void visit(AstTypedef* nodep) override { if (nodep->user1SetOnce()) return; iterateChildren(nodep); - AstStructDType* const dtypep = VN_CAST(nodep->dtypep(), StructDType); + AstNodeUOrStructDType* const dtypep = VN_CAST(nodep->dtypep(), NodeUOrStructDType); if (dtypep && !dtypep->packed()) { dtypep->name(nodep->name()); setStructModulep(dtypep); diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index bcd392abd..8d0718700 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -87,7 +87,8 @@ private: } void computeCppWidth(AstNode* nodep) { if (!nodep->user2() && nodep->hasDType()) { - if (VN_IS(nodep, Var) + if (VN_IS(nodep, Var) // + || VN_IS(nodep, ConsPackMember) // || VN_IS(nodep, NodeDType) // Don't want to change variable widths! || VN_IS(nodep->dtypep()->skipRefp(), AssocArrayDType) // Or arrays || VN_IS(nodep->dtypep()->skipRefp(), WildcardArrayDType) @@ -97,9 +98,9 @@ private: || VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType) || VN_IS(nodep->dtypep()->skipRefp(), VoidDType)) { } else { - const AstStructDType* const dtypep - = VN_CAST(nodep->dtypep()->skipRefp(), StructDType); - if (!dtypep || dtypep->packed()) { setCppWidth(nodep); } + const AstNodeUOrStructDType* const dtypep + = VN_CAST(nodep->dtypep()->skipRefp(), NodeUOrStructDType); + if (!dtypep || dtypep->packed()) setCppWidth(nodep); } } } diff --git a/src/V3Common.cpp b/src/V3Common.cpp index 5e589d4d7..72f900eb1 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -61,7 +61,7 @@ static void makeVlToString(AstIface* nodep) { funcp->addStmtsp(new AstCReturn{nodep->fileline(), exprp}); nodep->addStmtsp(funcp); } -static void makeVlToString(AstStructDType* nodep) { +static void makeVlToString(AstNodeUOrStructDType* nodep) { AstNodeModule* const modp = nodep->classOrPackagep(); AstCFunc* const funcp = new AstCFunc{nodep->fileline(), "VL_TO_STRING", nullptr, "std::string"}; @@ -79,7 +79,7 @@ static void makeVlToString(AstStructDType* nodep) { } else { stmt += ", "; } - stmt += itemp->nameProtect() + ":\" + "; + stmt += VIdProtect::protect(itemp->prettyName()) + ":\" + "; if (VN_IS(itemp->dtypep()->skipRefp(), BasicDType) && itemp->isWide()) { stmt += "VL_TO_STRING_W"; } else { @@ -168,7 +168,7 @@ void V3Common::commonAll() { } for (AstNode* nodep = v3Global.rootp()->typeTablep()->typesp(); nodep; nodep = nodep->nextp()) { - if (AstStructDType* const dtypep = VN_CAST(nodep, StructDType)) { + if (AstNodeUOrStructDType* const dtypep = VN_CAST(nodep, NodeUOrStructDType)) { if (!dtypep->packed()) makeVlToString(dtypep); } } diff --git a/src/V3Config.cpp b/src/V3Config.cpp index f5018d8cc..b6ede32c0 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -332,8 +332,7 @@ public: } bool waive(V3ErrorCode code, const string& match) { for (const auto& itr : m_waivers) { - if (((itr.first == code) || (itr.first == V3ErrorCode::I_LINT) - || (code.unusedError() && itr.first == V3ErrorCode::I_UNUSED)) + if ((code.isUnder(itr.first) || (itr.first == V3ErrorCode::I_LINT)) && VString::wildmatch(match, itr.second)) { return true; } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index c2f9b3d60..dc195e158 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -900,6 +900,7 @@ private: bool m_doV = false; // Verilog, not C++ conversion bool m_doGenerate = false; // Postpone width checking inside generate bool m_hasJumpDelay = false; // JumpGo or Delay under this while + bool m_underRecFunc = false; // Under a recursive function AstNodeModule* m_modp = nullptr; // Current module const AstArraySel* m_selp = nullptr; // Current select const AstNode* m_scopep = nullptr; // Current scope @@ -1384,15 +1385,6 @@ private: // but for now can disable en masse until V3Purify takes effect. return m_doShort || VN_IS(nodep, VarRef) || VN_IS(nodep, Const); } - bool isTreePureRecurse(AstNode* nodep) { - // Should memoize this if call commonly - if (!nodep->isPure()) return false; - if (nodep->op1p() && !isTreePureRecurse(nodep->op1p())) return false; - if (nodep->op2p() && !isTreePureRecurse(nodep->op2p())) return false; - if (nodep->op3p() && !isTreePureRecurse(nodep->op3p())) return false; - if (nodep->op4p() && !isTreePureRecurse(nodep->op4p())) return false; - return true; - } // Extraction checks bool warnSelect(AstSel* nodep) { @@ -1466,6 +1458,7 @@ private: if (!thensp->lhsp()->sameGateTree(elsesp->lhsp())) return false; if (!thensp->rhsp()->gateTree()) return false; if (!elsesp->rhsp()->gateTree()) return false; + if (m_underRecFunc) return false; // This optimization may lead to infinite recursion return true; } bool operandIfIf(const AstNodeIf* nodep) { @@ -2954,7 +2947,7 @@ private: } VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (!afterComment(nodep->thensp()) && !afterComment(nodep->elsesp())) { - if (!isTreePureRecurse(nodep->condp())) { + if (!nodep->condp()->isTreePureRecurse()) { // Condition has side effect - leave - perhaps in // future simplify to remove all but side effect terms } else { @@ -3094,12 +3087,12 @@ private: if (!inPct && ch == '%') { inPct = true; fmt = ch; - } else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) { + } else if (inPct && (std::isdigit(ch) || ch == '.' || ch == '-')) { fmt += ch; } else if (inPct) { inPct = false; fmt += ch; - switch (tolower(ch)) { + switch (std::tolower(ch)) { case '%': break; // %% - just output a % case 'm': break; // %m - auto insert "name" case 'l': break; // %l - auto insert "library" @@ -3137,6 +3130,11 @@ private: VL_DO_DANGLING(replaceConstString(nodep, nodep->name()), nodep); } } + void visit(AstNodeFTask* nodep) override { + VL_RESTORER(m_underRecFunc); + if (nodep->recursive()) m_underRecFunc = true; + iterateChildren(nodep); + } void visit(AstFuncRef* nodep) override { iterateChildren(nodep); diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index 88e61becf..340668e71 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -124,7 +124,10 @@ private: UINFO(9, "new " << declp << endl); AstCoverInc* const incp = new AstCoverInc{fl, declp}; - if (!trace_var_name.empty() && v3Global.opt.traceCoverage()) { + if (!trace_var_name.empty() + && v3Global.opt.traceCoverage() + // No module handle to trace inside classes + && !VN_IS(m_modp, Class)) { FileLine* const fl_nowarn = new FileLine{incp->fileline()}; fl_nowarn->modifyWarnOff(V3ErrorCode::UNUSEDSIGNAL, true); AstVar* const varp = new AstVar{fl_nowarn, VVarType::MODULETEMP, trace_var_name, diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 2b45be47f..5faad31e1 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -324,7 +324,7 @@ private: } } bool shouldDeleteTypedef(AstTypedef* typedefp) { - if (auto* structp = VN_CAST(typedefp->subDTypep(), StructDType)) { + if (auto* const structp = VN_CAST(typedefp->subDTypep(), NodeUOrStructDType)) { if (structp->user1() && !structp->packed()) return false; } return m_elimCells && !typedefp->attrPublic(); diff --git a/src/V3Dfg.h b/src/V3Dfg.h index ff6908d43..88c868192 100644 --- a/src/V3Dfg.h +++ b/src/V3Dfg.h @@ -503,14 +503,19 @@ public: inline bool inlined() const; // Methods that allow DfgVertex to participate in error reporting/messaging - void v3errorEnd(std::ostringstream& str) const { m_filelinep->v3errorEnd(str); } - void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN { + void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { + m_filelinep->v3errorEnd(str); + } + void v3errorEndFatal(std::ostringstream& str) const VL_ATTR_NORETURN + VL_REQUIRES(V3Error::s().m_mutex) { m_filelinep->v3errorEndFatal(str); } - string warnContextPrimary() const { return fileline()->warnContextPrimary(); } + string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) { + return fileline()->warnContextPrimary(); + } string warnContextSecondary() const { return fileline()->warnContextSecondary(); } - string warnMore() const { return fileline()->warnMore(); } - string warnOther() const { return fileline()->warnOther(); } + string warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnMore(); } + string warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { return fileline()->warnOther(); } private: // For internal use only. diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index 0184a8b88..7f60b5371 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -155,7 +155,7 @@ void EmitCFunc::emitOpName(AstNode* nodep, const string& format, AstNode* lhsp, puts("("); } else { // Normal text - if (isalnum(pos[0])) needComma = true; + if (std::isalnum(pos[0])) needComma = true; COMMA; string s; s += pos[0]; @@ -262,7 +262,7 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const } if (argp->widthMin() > 8 && fmtLetter == 'c') { // Technically legal, but surely not what the user intended. - argp->v3warn(WIDTH, dispp->verilogKwd() << "of %c format of > 8 bit value"); + argp->v3warn(WIDTHTRUNC, dispp->verilogKwd() << "of %c format of > 8 bit value"); } } // string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter; @@ -329,7 +329,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri m_emitDispState.pushFormat(*pos); } else { // Format character inPct = false; - switch (tolower(pos[0])) { + switch (std::tolower(pos[0])) { case '0': // FALLTHRU case '1': // FALLTHRU case '2': // FALLTHRU @@ -541,6 +541,12 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string if (int(nodep->num().toDouble()) == nodep->num().toDouble() && nodep->num().toDouble() < 1000 && nodep->num().toDouble() > -1000) { ofp()->printf("%3.1f", nodep->num().toDouble()); // Force decimal point + } else if (std::isinf(nodep->num().toDouble())) { + if (std::signbit(nodep->num().toDouble())) puts("-"); + ofp()->puts("std::numeric_limits::infinity()"); + } else if (std::isnan(nodep->num().toDouble())) { + if (std::signbit(nodep->num().toDouble())) puts("-"); + ofp()->puts("std::numeric_limits::quiet_NaN()"); } else { // Not %g as will not always put in decimal point, so not obvious to compiler // is a real number @@ -673,8 +679,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP depth + 1, suffix + "[" + ivar + "]"); const string post = "}\n"; return below.empty() ? "" : pre + below + post; - } else if (VN_IS(dtypep, StructDType) && !VN_AS(dtypep, StructDType)->packed()) { - const auto* const sdtypep = VN_AS(dtypep, StructDType); + } else if (VN_IS(dtypep, NodeUOrStructDType) && !VN_AS(dtypep, NodeUOrStructDType)->packed()) { + const auto* const sdtypep = VN_AS(dtypep, NodeUOrStructDType); string literal; for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 7f1078505..c91112ef0 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -624,9 +624,14 @@ public: puts(")"); } void visit(AstFError* nodep) override { - puts("VL_FERROR_IN("); + puts("VL_FERROR_I"); + puts(nodep->strp()->isString() ? "N(" : "W("); iterateAndNextNull(nodep->filep()); putbs(", "); + if (nodep->strp()->isWide()) { + puts(cvtToStr(nodep->strp()->widthWords())); + putbs(", "); + } iterateAndNextNull(nodep->strp()); puts(")"); } @@ -1262,6 +1267,22 @@ public: puts(")"); } } + void visit(AstConsPackUOrStruct* nodep) override { + putbs(nodep->dtypep()->cType("", false, false)); + puts("{"); + for (AstNode* memberp = nodep->membersp(); memberp; memberp = memberp->nextp()) { + iterate(memberp); + if (memberp->nextp()) { puts(", "); } + } + puts("}"); + } + void visit(AstConsPackMember* nodep) override { + auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType); + putbs("."); + puts(vdtypep->name()); + puts(" = "); + iterate(nodep->rhsp()); + } void visit(AstConsQueue* nodep) override { putbs(nodep->dtypep()->cType("", false, false)); if (!nodep->lhsp()) { diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 744e13baf..eadea126f 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -161,7 +161,7 @@ class EmitCHeader final : public EmitCConstInit { puts("void " + protect("__Vconfigure") + "(bool first);\n"); } - if (v3Global.opt.coverage()) { + if (v3Global.opt.coverage() && !VN_IS(modp, Class)) { decorateFirst(first, section); puts("void __vlCoverInsert("); puts(v3Global.opt.threads() ? "std::atomic" : "uint32_t"); @@ -208,13 +208,13 @@ class EmitCHeader final : public EmitCConstInit { } } } - void emitStructDecl(const AstNodeModule* modp, AstStructDType* sdtypep, - std::set& emitted) { + void emitStructDecl(const AstNodeModule* modp, AstNodeUOrStructDType* sdtypep, + std::set& emitted) { if (emitted.count(sdtypep) > 0) return; emitted.insert(sdtypep); for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { - AstStructDType* subp = VN_CAST(itemp->skipRefp(), StructDType); + AstNodeUOrStructDType* subp = VN_CAST(itemp->skipRefp(), NodeUOrStructDType); if (subp && !subp->packed()) { // Recurse if it belongs to the current module if (subp->classOrPackagep() == modp) { @@ -223,7 +223,8 @@ class EmitCHeader final : public EmitCConstInit { } } } - puts("struct " + EmitCBaseVisitor::prefixNameProtect(sdtypep) + " {\n"); + puts(sdtypep->verilogKwd()); // "struct"/"union" + puts(" " + EmitCBaseVisitor::prefixNameProtect(sdtypep) + " {\n"); for (const AstMemberDType* itemp = sdtypep->membersp(); itemp; itemp = VN_AS(itemp->nextp(), MemberDType)) { puts(itemp->dtypep()->cType(itemp->nameProtect(), false, false)); @@ -234,12 +235,12 @@ class EmitCHeader final : public EmitCConstInit { void emitStructs(const AstNodeModule* modp) { bool first = true; // Track structs that've been emitted already - std::set emitted; + std::set emitted; for (const AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { const AstTypedef* const tdefp = VN_CAST(nodep, Typedef); if (!tdefp) continue; - AstStructDType* const sdtypep - = VN_CAST(tdefp->dtypep()->skipRefToEnump(), StructDType); + AstNodeUOrStructDType* const sdtypep + = VN_CAST(tdefp->dtypep()->skipRefToEnump(), NodeUOrStructDType); if (!sdtypep) continue; if (sdtypep->packed()) continue; decorateFirst(first, "\n// UNPACKED STRUCT TYPES\n"); diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index 16e24ac64..8bfc9fcfc 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -50,7 +50,8 @@ class EmitCGatherDependencies final : VNVisitor { if (const AstClassRefDType* const dtypep = VN_CAST(nodep, ClassRefDType)) { m_dependencies.insert( EmitCBaseVisitor::prefixNameProtect(dtypep->classp()->classOrPackagep())); - } else if (const AstStructDType* const dtypep = VN_CAST(nodep, StructDType)) { + } else if (const AstNodeUOrStructDType* const dtypep + = VN_CAST(nodep, NodeUOrStructDType)) { if (!dtypep->packed()) { m_dependencies.insert( EmitCBaseVisitor::prefixNameProtect(dtypep->classOrPackagep())); @@ -454,9 +455,9 @@ class EmitCImp final : EmitCFunc { emitCtorImp(modp); emitConfigureImp(modp); emitDestructorImp(modp); + emitCoverageImp(); } emitSavableImp(modp); - emitCoverageImp(); } else { // From `systemc_implementation emitTextSection(modp, VNType::atScImp); diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 8b3e75d84..2ae694b48 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -156,6 +156,22 @@ class EmitCSyms final : EmitCBaseVisitor { string out = scpname; // Remove hierarchy string::size_type pos = out.rfind('.'); + + // If there's more than one ident and an escape, find the true last ident + if (pos != string::npos && scpname.find('\\') != string::npos) { + size_t i = 0; + // always makes progress + while (i < scpname.length()) { + if (scpname[i] == '\\') { + while (i < scpname.length() && scpname[i] != ' ') ++i; + ++i; // Proc ' ', it should always be there. Then grab '.' on next cycle + } else { + while (i < scpname.length() && scpname[i] != '.') ++i; + if (i < scpname.length()) { pos = i++; } + } + } + } + if (pos != std::string::npos) out.erase(0, pos + 1); // Decode all escaped characters while ((pos = out.find("__0")) != string::npos) { @@ -170,7 +186,7 @@ class EmitCSyms final : EmitCBaseVisitor { void varHierarchyScopes(string scp) { while (!scp.empty()) { - const auto scpit = m_vpiScopeCandidates.find(scp); + const auto scpit = m_vpiScopeCandidates.find(scopeSymString(scp)); if ((scpit != m_vpiScopeCandidates.end()) && (m_scopeNames.find(scp) == m_scopeNames.end())) { const auto scopeNameit = m_scopeNames.find(scpit->second.m_symName); @@ -219,19 +235,19 @@ class EmitCSyms final : EmitCBaseVisitor { } // UINFO(9, "For " << scopep->name() << " - " << varp->name() << " Scp " // << scpName << "Var " << varBase << endl); - const string varBasePretty = AstNode::prettyName(varBase); - const string scpPretty = AstNode::prettyName(scpName); - const string scpSym = scopeSymString(scpName); + const string varBasePretty = AstNode::prettyName(VName::dehash(varBase)); + const string scpPretty = AstNode::prettyName(VName::dehash(scpName)); + const string scpSym = scopeSymString(VName::dehash(scpName)); // UINFO(9, " scnameins sp " << scpName << " sp " << scpPretty << " ss " // << scpSym << endl); if (v3Global.opt.vpi()) varHierarchyScopes(scpName); if (m_scopeNames.find(scpSym) == m_scopeNames.end()) { m_scopeNames.insert(std::make_pair( - scpSym, ScopeData(scpSym, scpPretty, 0, "SCOPE_OTHER"))); + scpSym, ScopeData{scpSym, scpPretty, 0, "SCOPE_OTHER"})); } m_scopeVars.insert( std::make_pair(scpSym + " " + varp->name(), - ScopeVarData(scpSym, varBasePretty, varp, modp, scopep))); + ScopeVarData{scpSym, varBasePretty, varp, modp, scopep})); } } } @@ -296,10 +312,11 @@ class EmitCSyms final : EmitCBaseVisitor { const string type = (nodep->origModName() == "__BEGIN__") ? "SCOPE_OTHER" : "SCOPE_MODULE"; const string name = nodep->scopep()->shortName() + "__DOT__" + nodep->name(); - const string name_dedot = AstNode::dedotName(name); + const string name_pretty = AstNode::vpiName(name); const int timeunit = m_modp->timeunit().powerOfTen(); m_vpiScopeCandidates.insert( - std::make_pair(name, ScopeData(scopeSymString(name), name_dedot, timeunit, type))); + std::make_pair(scopeSymString(name), + ScopeData{scopeSymString(name), name_pretty, timeunit, type})); } } void visit(AstScope* nodep) override { @@ -310,20 +327,20 @@ class EmitCSyms final : EmitCBaseVisitor { if (v3Global.opt.vpi() && !nodep->isTop()) { const string type = VN_IS(nodep->modp(), Package) ? "SCOPE_OTHER" : "SCOPE_MODULE"; - const string name_dedot = AstNode::dedotName(nodep->shortName()); + const string name_pretty = AstNode::vpiName(nodep->shortName()); const int timeunit = m_modp->timeunit().powerOfTen(); - m_vpiScopeCandidates.insert( - std::make_pair(nodep->name(), ScopeData(scopeSymString(nodep->name()), name_dedot, - timeunit, type))); + m_vpiScopeCandidates.insert(std::make_pair( + scopeSymString(nodep->name()), + ScopeData{scopeSymString(nodep->name()), name_pretty, timeunit, type})); } } void visit(AstScopeName* nodep) override { const string name = nodep->scopeSymName(); - // UINFO(9,"scnameins sp "<name()<<" sp "<scopePrettySymName() - // <<" ss"<name() << " sp " << nodep->scopePrettySymName() + // << " ss" << name << endl); const int timeunit = m_modp ? m_modp->timeunit().powerOfTen() : 0; m_scopeNames.emplace( - name, ScopeData(name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER")); + name, ScopeData{name, nodep->scopePrettySymName(), timeunit, "SCOPE_OTHER"}); if (nodep->dpiExport()) { UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function"); m_scopeFuncs.insert(std::make_pair(name + " " + m_cfuncp->name(), @@ -332,8 +349,8 @@ class EmitCSyms final : EmitCBaseVisitor { if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) { m_scopeNames.insert( std::make_pair(nodep->scopeDpiName(), - ScopeData(nodep->scopeDpiName(), nodep->scopePrettyDpiName(), - timeunit, "SCOPE_OTHER"))); + ScopeData{nodep->scopeDpiName(), nodep->scopePrettyDpiName(), + timeunit, "SCOPE_OTHER"})); } } } diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index f55c3c074..d9f05b302 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -614,12 +614,17 @@ class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { iterate(nodep->subDTypep()); iterateAndNextConstNull(nodep->rangep()); } + void visit(AstRefDType* nodep) override { iterate(nodep->skipRefp()); } void visit(AstNodeUOrStructDType* nodep) override { puts(nodep->verilogKwd() + " "); if (nodep->packed()) puts("packed "); puts("\n"); puts("{"); - iterateAndNextConstNull(nodep->membersp()); + for (AstMemberDType* itemp = nodep->membersp(); itemp; + itemp = VN_AS(itemp->nextp(), MemberDType)) { + iterate(itemp); + puts(";"); + } puts("}"); } void visit(AstMemberDType* nodep) override { diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 0a3515219..2f1a01f20 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -25,24 +25,6 @@ VL_DEFINE_DEBUG_FUNCTIONS; // clang-format on //====================================================================== -// Statics - -int V3Error::s_errCount = 0; -int V3Error::s_warnCount = 0; -int V3Error::s_debugDefault = 0; -int V3Error::s_errorLimit = V3Error::MAX_ERRORS; -bool V3Error::s_warnFatal = true; -int V3Error::s_tellManual = 0; -std::ostringstream V3Error::s_errorStr; // Error string being formed -V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL; -bool V3Error::s_errorContexted = false; -bool V3Error::s_errorSuppressed = false; -std::array V3Error::s_describedEachWarn; -std::array V3Error::s_pretendError; -bool V3Error::s_describedWarnings = false; -bool V3Error::s_describedWeb = false; -V3Error::MessagesSet V3Error::s_messages; -V3Error::ErrorExitCb V3Error::s_errorExitCb = nullptr; struct v3errorIniter { v3errorIniter() { V3Error::init(); } @@ -65,51 +47,10 @@ V3ErrorCode::V3ErrorCode(const char* msgp) { } //###################################################################### -// V3Error class functions +// V3ErrorGuarded class functions +// -void V3Error::init() { - for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) { - s_describedEachWarn[i] = false; - s_pretendError[i] = V3ErrorCode{i}.pretendError(); - } - if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) { - v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged"); - } -} - -string V3Error::lineStr(const char* filename, int lineno) { - std::ostringstream out; - const char* const fnslashp = std::strrchr(filename, '/'); - if (fnslashp) filename = fnslashp + 1; - out << filename << ":" << std::dec << lineno << ":"; - const char* const spaces = " "; - size_t numsp = out.str().length(); - if (numsp > 20) numsp = 20; - out << (spaces + numsp); - return out.str(); -} - -void V3Error::incErrors() { - s_errCount++; - if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse - v3fatalExit("Exiting due to too many errors encountered; --error-limit=" // - << errorCount() << endl); - } -} - -void V3Error::abortIfWarnings() { - const bool exwarn = warnFatal() && warnCount(); - if (errorCount() && exwarn) { - v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s), " // - << warnCount() << " warning(s)\n"); - } else if (errorCount()) { - v3fatalExit("Exiting due to " << std::dec << errorCount() << " error(s)\n"); - } else if (exwarn) { - v3fatalExit("Exiting due to " << std::dec << warnCount() << " warning(s)\n"); - } -} - -bool V3Error::isError(V3ErrorCode code, bool supp) { +bool V3ErrorGuarded::isError(V3ErrorCode code, bool supp) VL_REQUIRES(m_mutex) { if (supp) { return false; } else if (code == V3ErrorCode::USERINFO) { @@ -124,16 +65,16 @@ bool V3Error::isError(V3ErrorCode code, bool supp) { return true; } else if (code == V3ErrorCode::EC_ERROR) { return true; - } else if (code < V3ErrorCode::EC_FIRST_WARN || s_pretendError[code]) { + } else if (code < V3ErrorCode::EC_FIRST_WARN || pretendError(code)) { return true; } else { return false; } } -string V3Error::msgPrefix() { - const V3ErrorCode code = s_errorCode; - const bool supp = s_errorSuppressed; +string V3ErrorGuarded::msgPrefix() VL_REQUIRES(m_mutex) { + const V3ErrorCode code = m_errorCode; + const bool supp = m_errorSuppressed; if (supp) { return "-arning-suppressed: "; } else if (code == V3ErrorCode::USERINFO) { @@ -155,10 +96,7 @@ string V3Error::msgPrefix() { } } -//====================================================================== -// Abort/exit - -void V3Error::vlAbortOrExit() { +void V3ErrorGuarded::vlAbortOrExit() VL_REQUIRES(m_mutex) { if (V3Error::debugDefault()) { std::cerr << msgPrefix() << "Aborting since under --debug" << endl; V3Error::vlAbort(); @@ -167,50 +105,53 @@ void V3Error::vlAbortOrExit() { } } -void V3Error::vlAbort() { - VL_GCOV_DUMP(); - std::abort(); -} +string V3ErrorGuarded::warnMore() VL_REQUIRES(m_mutex) { return string(msgPrefix().size(), ' '); } -//====================================================================== -// Global Functions - -void V3Error::suppressThisWarning() { +void V3ErrorGuarded::suppressThisWarning() VL_REQUIRES(m_mutex) { #ifndef V3ERROR_NO_GLOBAL_ - V3Stats::addStatSum(std::string{"Warnings, Suppressed "} + s_errorCode.ascii(), 1); + V3Stats::addStatSum(std::string{"Warnings, Suppressed "} + errorCode().ascii(), 1); #endif - s_errorSuppressed = true; + errorSuppressed(true); } -string V3Error::warnMore() { return string(msgPrefix().size(), ' '); } - // cppcheck-has-bug-suppress constParameter -void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) { +void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra) + VL_REQUIRES(m_mutex) { #if defined(__COVERITY__) || defined(__cppcheck__) - if (s_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x); + if (m_errorCode == V3ErrorCode::EC_FATAL) __coverity_panic__(x); #endif // Skip suppressed messages - if (s_errorSuppressed + if (m_errorSuppressed // On debug, show only non default-off warning to prevent pages of warnings - && (!debug() || s_errorCode.defaultsOff())) + && (!debug() || m_errorCode.defaultsOff())) return; string msg = msgPrefix() + sstr.str(); - if (s_errorSuppressed) { // If suppressed print only first line to reduce verbosity + // If suppressed print only first line to reduce verbosity + if (m_errorSuppressed) { string::size_type pos; if ((pos = msg.find('\n')) != string::npos) { msg.erase(pos, msg.length() - pos); msg += "..."; } } + string msg_additional; + { + string::size_type pos; + if ((pos = msg.find(V3Error::warnAdditionalInfo())) != string::npos) { + msg_additional = msg.substr(pos + V3Error::warnAdditionalInfo().size()); + msg.erase(pos); + } + } // Trailing newline (generally not on messages) & remove dup newlines { msg += '\n'; // Trailing newlines generally not put on messages so add string::size_type pos; while ((pos = msg.find("\n\n")) != string::npos) msg.erase(pos + 1, 1); + while ((pos = msg_additional.find("\n\n")) != string::npos) + msg_additional.erase(pos + 1, 1); } // Suppress duplicate messages - if (s_messages.find(msg) != s_messages.end()) return; - s_messages.insert(msg); + if (!m_messages.insert(msg).second) return; if (!extra.empty()) { const string extraMsg = warnMore() + extra + "\n"; const size_t pos = msg.find('\n'); @@ -219,44 +160,45 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) { // Output if ( #ifndef V3ERROR_NO_GLOBAL_ - !(v3Global.opt.quietExit() && s_errorCode == V3ErrorCode::EC_FATALEXIT) + !(v3Global.opt.quietExit() && m_errorCode == V3ErrorCode::EC_FATALEXIT) #else true #endif ) { std::cerr << msg; } - if (!s_errorSuppressed - && !(s_errorCode == V3ErrorCode::EC_INFO || s_errorCode == V3ErrorCode::USERINFO)) { - const bool anError = isError(s_errorCode, s_errorSuppressed); - if (s_errorCode >= V3ErrorCode::EC_FIRST_NAMED && !s_describedWeb) { - s_describedWeb = true; + if (!m_errorSuppressed + && !(m_errorCode == V3ErrorCode::EC_INFO || m_errorCode == V3ErrorCode::USERINFO)) { + const bool anError = isError(m_errorCode, m_errorSuppressed); + if (m_errorCode >= V3ErrorCode::EC_FIRST_NAMED && !m_describedWeb) { + m_describedWeb = true; std::cerr << warnMore() << "... For " << (anError ? "error" : "warning") - << " description see https://verilator.org/warn/" << s_errorCode.ascii() + << " description see https://verilator.org/warn/" << m_errorCode.ascii() << "?v=" << PACKAGE_VERSION_NUMBER_STRING << endl; } - if (!s_describedEachWarn[s_errorCode] && !s_pretendError[s_errorCode]) { - s_describedEachWarn[s_errorCode] = true; - if (s_errorCode >= V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) { - s_describedWarnings = true; + if (!m_describedEachWarn[m_errorCode] && !m_pretendError[m_errorCode]) { + m_describedEachWarn[m_errorCode] = true; + if (m_errorCode >= V3ErrorCode::EC_FIRST_WARN && !m_describedWarnings) { + m_describedWarnings = true; std::cerr << warnMore() << "... Use \"/* verilator lint_off " - << s_errorCode.ascii() + << m_errorCode.ascii() << " */\" and lint_on around source to disable this message." << endl; } - if (s_errorCode.dangerous()) { + if (m_errorCode.dangerous()) { std::cerr << warnMore() << "*** See https://verilator.org/warn/" - << s_errorCode.ascii() << " before disabling this,\n"; + << m_errorCode.ascii() << " before disabling this,\n"; std::cerr << warnMore() << "else you may end up with different sim results." << endl; } } + if (!msg_additional.empty()) { std::cerr << msg_additional; } // If first warning is not the user's fault (internal/unsupported) then give the website // Not later warnings, as a internal may be caused by an earlier problem - if (s_tellManual == 0) { - if (s_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) { - s_tellManual = 1; + if (tellManual() == 0) { + if (m_errorCode.mentionManual() || sstr.str().find("Unsupported") != string::npos) { + tellManual(1); } else { - s_tellManual = 2; + tellManual(2); } } if (anError) { @@ -264,26 +206,34 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) { } else { incWarnings(); } - if (s_errorCode == V3ErrorCode::EC_FATAL || s_errorCode == V3ErrorCode::EC_FATALEXIT - || s_errorCode == V3ErrorCode::EC_FATALSRC) { + if (m_errorCode == V3ErrorCode::EC_FATAL || m_errorCode == V3ErrorCode::EC_FATALEXIT + || m_errorCode == V3ErrorCode::EC_FATALSRC) { static bool inFatal = false; if (!inFatal) { inFatal = true; - if (s_tellManual == 1) { + if (tellManual() == 1) { std::cerr << warnMore() << "... See the manual at https://verilator.org/verilator_doc.html " "for more assistance." << endl; - s_tellManual = 2; + tellManual(2); } #ifndef V3ERROR_NO_GLOBAL_ - if (dumpTree()) { - v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree", 990)); - } - if (debug()) { - if (s_errorExitCb) s_errorExitCb(); - V3Stats::statsFinalAll(v3Global.rootp()); - V3Stats::statsReport(); + if (dumpTree() || debug()) { + V3ThreadPool::s().requestExclusiveAccess([&]() VL_REQUIRES(m_mutex) { + if (dumpTree()) { + v3Global.rootp()->dumpTreeFile( + v3Global.debugFilename("final.tree", 990)); + } + if (debug()) { + execErrorExitCb(); + V3Stats::statsFinalAll(v3Global.rootp()); + V3Stats::statsReport(); + } + // Abort in exclusive access to make sure other threads + // don't change error code + vlAbortOrExit(); + }); } #endif } @@ -292,7 +242,52 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& extra) { } else if (anError) { // We don't dump tree on any error because a Visitor may be in middle of // a tree cleanup and cause a false broken problem. - if (s_errorExitCb) s_errorExitCb(); + execErrorExitCb(); } } } + +//###################################################################### +// V3Error class functions + +void V3Error::init() { + for (int i = 0; i < V3ErrorCode::_ENUM_MAX; i++) { + describedEachWarn(static_cast(i), false); + pretendError(static_cast(i), V3ErrorCode{i}.pretendError()); + } + if (VL_UNCOVERABLE(string(V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()) != " MAX")) { + v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged"); + } +} + +string V3Error::lineStr(const char* filename, int lineno) VL_PURE { + std::ostringstream out; + const char* const fnslashp = std::strrchr(filename, '/'); + if (fnslashp) filename = fnslashp + 1; + out << filename << ":" << std::dec << lineno << ":"; + const char* const spaces = " "; + size_t numsp = out.str().length(); + if (numsp > 20) numsp = 20; + out << (spaces + numsp); + return out.str(); +} + +void V3Error::abortIfWarnings() { + const bool exwarn = warnFatal() && warnCount(); + if (errorCount() && exwarn) { + v3fatalExit("Exiting due to " << std::dec << V3Error::s().errorCount() << " error(s), " // + << V3Error::s().warnCount() << " warning(s)\n"); + } else if (errorCount()) { + v3fatalExit("Exiting due to " << std::dec << V3Error::s().errorCount() << " error(s)\n"); + } else if (exwarn) { + v3fatalExit("Exiting due to " << std::dec << V3Error::s().warnCount() << " warning(s)\n"); + } +} + +//====================================================================== +// Abort/exit + +void V3Error::vlAbort() { + VL_GCOV_DUMP(); + std::abort(); +} diff --git a/src/V3Error.h b/src/V3Error.h index 1dc8e2487..05f865f13 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -20,8 +20,13 @@ #include "config_build.h" #include "verilatedos.h" +#include "verilated_threads.h" + // Limited V3 headers here - this is a base class for Vlc etc #include "V3String.h" +#ifndef V3ERROR_NO_GLOBAL_ +#include "V3ThreadPool.h" +#endif #include #include @@ -77,7 +82,7 @@ public: CASEWITHX, // Case with X values CASEX, // Casex CASTCONST, // Cast is constant - CDCRSTLOGIC, // Logic in async reset path + CDCRSTLOGIC, // Logic in async reset path. Historical, never issued. CLKDATA, // Clock used as data. Historical, never issued. CMPCONST, // Comparison is constant due to limited range COLONPLUS, // :+ instead of +: @@ -147,6 +152,9 @@ public: VARHIDDEN, // Hiding variable WAITCONST, // Wait condition is constant WIDTH, // Width mismatch + WIDTHTRUNC, // Width mismatch- lhs < rhs + WIDTHEXPAND, // Width mismatch- lhs > rhs + WIDTHXZEXPAND, // Width mismatch- lhs > rhs xz filled WIDTHCONCAT, // Unsized numbers/parameters in concatenations ZERODLY, // #0 delay _ENUM_MAX @@ -184,7 +192,7 @@ public: "IMPERFECTSCH", "IMPLICIT", "IMPLICITSTATIC", "IMPORTSTAR", "IMPURE", "INCABSPATH", "INFINITELOOP", "INITIALDLY", "INSECURE", "LATCH", "LITENDIAN", "MINTYPMAXDLY", "MODDUP", - "MULTIDRIVEN", "MULTITOP","NOLATCH", "NULLPORT", "PINCONNECTEMPTY", + "MULTIDRIVEN", "MULTITOP", "NOLATCH", "NULLPORT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PROCASSWIRE", "PROFOUTOFDATE", "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "RISEFALLDLY", "SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", @@ -192,7 +200,7 @@ public: "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", - "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "ZERODLY", + "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHTRUNC", "WIDTHEXPAND", "WIDTHXZEXPAND", "WIDTHCONCAT", "ZERODLY", " MAX" }; // clang-format on @@ -223,7 +231,8 @@ public: || m_e == CASEOVERLAP || m_e == CASEWITHX || m_e == CASEX || m_e == CASTCONST || m_e == CMPCONST || m_e == COLONPLUS || m_e == IMPLICIT || m_e == IMPLICITSTATIC || m_e == LATCH || m_e == LITENDIAN || m_e == PINMISSING || m_e == REALCVT - || m_e == UNSIGNED || m_e == WIDTH); + || m_e == UNSIGNED || m_e == WIDTH || m_e == WIDTHTRUNC || m_e == WIDTHEXPAND + || m_e == WIDTHXZEXPAND); } // Warnings that are style only bool styleError() const VL_MT_SAFE { @@ -238,6 +247,20 @@ public: bool unusedError() const VL_MT_SAFE { return (m_e == UNUSEDGENVAR || m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL); } + + bool isUnder(V3ErrorCode other) { + // backwards compatibility inheritance-like warnings + if (m_e == other) { return true; } + if (other == V3ErrorCode::WIDTH) { + return (m_e == WIDTH || m_e == WIDTHEXPAND || m_e == WIDTHTRUNC + || m_e == WIDTHXZEXPAND); + } + if (other == V3ErrorCode::I_UNUSED) { + return (m_e == UNUSEDGENVAR || m_e == UNUSEDPARAM || m_e == UNUSEDSIGNAL); + } + return false; + } + static bool unusedMsg(const char* msgp) { return 0 == VL_STRCASECMP(msgp, "UNUSED"); } }; constexpr bool operator==(const V3ErrorCode& lhs, const V3ErrorCode& rhs) { @@ -250,71 +273,224 @@ inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) { } // ###################################################################### - -class V3Error final { - // Base class for any object that wants debugging and error reporting - +class V3ErrorGuarded final { + // Should only be used by V3ErrorGuarded::m_mutex is already locked + // contains guarded members +public: using MessagesSet = std::set; using ErrorExitCb = void (*)(void); private: - static bool s_describedWarnings; // Told user how to disable warns - static bool s_describedWeb; // Told user to see web - static std::array - s_describedEachWarn; // Told user specifics about this warning - static std::array - s_pretendError; // Pretend this warning is an error - static int s_debugDefault; // Option: --debugi Default debugging level - static int s_errorLimit; // Option: --error-limit Number of errors before exit - static bool s_warnFatal; // Option: --warnFatal Warnings are fatal - static int s_errCount; // Error count - static int s_warnCount; // Warning count - static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable - static std::ostringstream s_errorStr; // Error string being formed - static V3ErrorCode s_errorCode; // Error string being formed will abort - static bool s_errorContexted; // Error being formed got context - static bool s_errorSuppressed; // Error being formed should be suppressed - static MessagesSet s_messages; // What errors we've outputted - static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping - static constexpr unsigned MAX_ERRORS = 50; // Fatal after this may errors + bool m_describedWarnings VL_GUARDED_BY(m_mutex) = false; // Told user how to disable warns + // Tell user to see manual, 0=not yet, 1=doit, 2=disable + int m_tellManual VL_GUARDED_BY(m_mutex) = 0; + V3ErrorCode m_errorCode VL_GUARDED_BY(m_mutex) + = V3ErrorCode::EC_FATAL; // Error string being formed will abort + bool m_errorSuppressed VL_GUARDED_BY(m_mutex) + = false; // Error being formed should be suppressed + MessagesSet m_messages VL_GUARDED_BY(m_mutex); // What errors we've outputted + ErrorExitCb m_errorExitCb VL_GUARDED_BY(m_mutex) + = nullptr; // Callback when error occurs for dumping + bool m_errorContexted VL_GUARDED_BY(m_mutex) = false; // Error being formed got context + int m_warnCount VL_GUARDED_BY(m_mutex) = 0; // Warning count + int m_errCount VL_GUARDED_BY(m_mutex) = 0; // Error count + // Pretend this warning is an error + std::array m_pretendError VL_GUARDED_BY(m_mutex); + bool m_describedWeb VL_GUARDED_BY(m_mutex) = false; // Told user to see web + // Told user specifics about this warning + std::array m_describedEachWarn VL_GUARDED_BY(m_mutex); + int m_debugDefault = 0; // Option: --debugi Default debugging level + int m_errorLimit VL_GUARDED_BY(m_mutex) + = MAX_ERRORS; // Option: --error-limit Number of errors before exit + bool m_warnFatal VL_GUARDED_BY(m_mutex) = true; // Option: --warnFatal Warnings are fatal + std::ostringstream m_errorStr VL_GUARDED_BY(m_mutex); // Error string being formed +public: + VerilatedMutex m_mutex; // Make sure only single thread is in class + + string msgPrefix() VL_REQUIRES(m_mutex); // returns %Error/%Warn + string warnMore() VL_REQUIRES(m_mutex); + void execErrorExitCb() VL_REQUIRES(m_mutex) { + if (m_errorExitCb) m_errorExitCb(); + } + void errorExitCb(ErrorExitCb cb) VL_REQUIRES(m_mutex) { m_errorExitCb = cb; } + ErrorExitCb errorExitCb() VL_REQUIRES(m_mutex) { return m_errorExitCb; } + bool isError(V3ErrorCode code, bool supp) VL_REQUIRES(m_mutex); + void vlAbortOrExit() VL_REQUIRES(m_mutex); + void errorContexted(bool flag) VL_REQUIRES(m_mutex) { m_errorContexted = flag; } + void incWarnings() VL_REQUIRES(m_mutex) { m_warnCount++; } + void incErrors() VL_REQUIRES(m_mutex) { + m_errCount++; + if (errorCount() == errorLimit()) { // Not >= as would otherwise recurse + v3errorEnd( + (v3errorPrep(V3ErrorCode::EC_FATALEXIT), + (v3errorStr() << "Exiting due to too many errors encountered; --error-limit=" + << errorCount() << endl), + v3errorStr())); + assert(0); // LCOV_EXCL_LINE + VL_UNREACHABLE; + } + } + int errorCount() VL_REQUIRES(m_mutex) { return m_errCount; } + bool pretendError(int errorCode) VL_REQUIRES(m_mutex) { return m_pretendError[errorCode]; } + void pretendError(V3ErrorCode code, bool flag) VL_REQUIRES(m_mutex) { + if (code == V3ErrorCode::WIDTH) { + m_pretendError[V3ErrorCode::WIDTHTRUNC] = flag; + m_pretendError[V3ErrorCode::WIDTHEXPAND] = flag; + m_pretendError[V3ErrorCode::WIDTHXZEXPAND] = flag; + } + m_pretendError[code] = flag; + } + void debugDefault(int level) VL_MT_UNSAFE { m_debugDefault = level; } + int debugDefault() VL_MT_SAFE { return m_debugDefault; } + void errorLimit(int level) VL_REQUIRES(m_mutex) { m_errorLimit = level; } + int errorLimit() VL_REQUIRES(m_mutex) { return m_errorLimit; } + void warnFatal(bool flag) VL_REQUIRES(m_mutex) { m_warnFatal = flag; } + bool warnFatal() VL_REQUIRES(m_mutex) { return m_warnFatal; } + void v3errorPrep(V3ErrorCode code) VL_REQUIRES(m_mutex) { + m_errorStr.str(""); + m_errorCode = code; + m_errorContexted = false; + m_errorSuppressed = false; + } + std::ostringstream& v3errorStr() VL_REQUIRES(m_mutex) { return m_errorStr; } + V3ErrorCode errorCode() VL_REQUIRES(m_mutex) { return m_errorCode; } + bool errorContexted() VL_REQUIRES(m_mutex) { return m_errorContexted; } + int warnCount() VL_REQUIRES(m_mutex) { return m_warnCount; } + bool errorSuppressed() VL_REQUIRES(m_mutex) { return m_errorSuppressed; } + void errorSuppressed(bool flag) VL_REQUIRES(m_mutex) { m_errorSuppressed = flag; } + bool describedWeb() VL_REQUIRES(m_mutex) { return m_describedWeb; } + void describedWeb(bool flag) VL_REQUIRES(m_mutex) { m_describedWeb = flag; } + bool describedEachWarn(V3ErrorCode code) VL_REQUIRES(m_mutex) { + return m_describedEachWarn[code]; + } + void describedEachWarn(V3ErrorCode code, bool flag) VL_REQUIRES(m_mutex) { + m_describedEachWarn[code] = flag; + } + bool describedWarnings() VL_REQUIRES(m_mutex) { return m_describedWarnings; } + void describedWarnings(bool flag) VL_REQUIRES(m_mutex) { m_describedWarnings = flag; } + int tellManual() VL_REQUIRES(m_mutex) { return m_tellManual; } + void tellManual(int level) VL_REQUIRES(m_mutex) { m_tellManual = level; } + void v3errorEnd(std::ostringstream& sstr, const string& extra = "") VL_REQUIRES(m_mutex); + void suppressThisWarning() VL_REQUIRES(m_mutex); + string warnContextNone() VL_REQUIRES(m_mutex) { + errorContexted(true); + return ""; + } +}; + +// ###################################################################### +class V3Error final { + // Base class for any object that wants debugging and error reporting +private: + // CONSTRUCTORS V3Error() { std::cerr << ("Static class"); V3Error::vlAbort(); } public: - // CONSTRUCTORS + static V3ErrorGuarded& s() VL_MT_SAFE { // Singleton + static V3ErrorGuarded s_s; + return s_s; + } + // ACCESSORS - static void debugDefault(int level) { s_debugDefault = level; } - static int debugDefault() VL_MT_SAFE { return s_debugDefault; } - static void errorLimit(int level) { s_errorLimit = level; } - static int errorLimit() VL_MT_SAFE { return s_errorLimit; } - static void warnFatal(bool flag) { s_warnFatal = flag; } - static bool warnFatal() { return s_warnFatal; } - static string msgPrefix(); // returns %Error/%Warn - static int errorCount() VL_MT_SAFE { return s_errCount; } - static int warnCount() { return s_warnCount; } - static bool errorContexted() VL_MT_SAFE { return s_errorContexted; } - static void errorContexted(bool flag) { s_errorContexted = flag; } + static void debugDefault(int level) VL_MT_UNSAFE { s().debugDefault(level); } + static int debugDefault() VL_MT_SAFE { return s().debugDefault(); } + static void errorLimit(int level) VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().errorLimit(level); + } + static int errorLimit() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().errorLimit(); + } + static void warnFatal(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().warnFatal(flag); + } + static bool warnFatal() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().warnFatal(); + } + // returns %Error/%Warn + static string msgPrefix() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().msgPrefix(); + } + static int errorCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().errorCount(); + } + static bool pretendError(int errorCode) VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().pretendError(errorCode); + } + static int warnCount() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().warnCount(); + } + static bool errorContexted() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().errorContexted(); + } + static void errorContexted(bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().errorContexted(flag); + } + static void describedEachWarn(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().describedEachWarn(code, flag); + } // METHODS - static void incErrors(); - static void incWarnings() { s_warnCount++; } + static void incErrors() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().incErrors(); + } + static void incWarnings() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().incWarnings(); + } static void init(); static void abortIfErrors() { if (errorCount()) abortIfWarnings(); } static void abortIfWarnings(); - static void suppressThisWarning(); // Suppress next %Warn if user has it off - static void pretendError(V3ErrorCode code, bool flag) { s_pretendError[code] = flag; } - static bool isError(V3ErrorCode code, bool supp); - static string lineStr(const char* filename, int lineno); - static V3ErrorCode errorCode() VL_MT_SAFE { return s_errorCode; } - static void errorExitCb(ErrorExitCb cb) { s_errorExitCb = cb; } + // Suppress next %Warn if user has it off + static void suppressThisWarning() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().suppressThisWarning(); + } + static void pretendError(V3ErrorCode code, bool flag) VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().pretendError(code, flag); + } + static string lineStr(const char* filename, int lineno) VL_PURE; + static V3ErrorCode errorCode() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().errorCode(); + } + static void errorExitCb(V3ErrorGuarded::ErrorExitCb cb) VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().errorExitCb(cb); + } // When printing an error/warning, print prefix for multiline message - static string warnMore(); + static string warnMore() VL_REQUIRES(s().m_mutex) { return s().warnMore(); } + // This function should only be used when it is impossible to + // generate whole error message inside v3warn macros and it needs to be + // streamed directly to cerr. + // Use with caution as this function isn't MT_SAFE. + static string warnMoreStandalone() VL_EXCLUDES(s().m_mutex) VL_MT_UNSAFE { + const VerilatedLockGuard guard{s().m_mutex}; + return s().warnMore(); + } + // This function marks place in error message from which point message + // should be printed after information on the error code. + // The post-processing is done in v3errorEnd function. + static string warnAdditionalInfo() VL_MT_SAFE { return "__WARNADDITIONALINFO__"; } /// When building an error, don't show context info static string warnContextNone() { V3Error::errorContexted(true); @@ -323,36 +499,66 @@ public: // Internals for v3error()/v3fatal() macros only // Error end takes the string stream to output, be careful to seek() as needed - static void v3errorPrep(V3ErrorCode code) { - s_errorStr.str(""); - s_errorCode = code; - s_errorContexted = false; - s_errorSuppressed = false; + static void v3errorPrep(V3ErrorCode code) VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + s().v3errorPrep(code); + } + static std::ostringstream& v3errorStr() VL_MT_SAFE_EXCLUDES(s().m_mutex) { + const VerilatedLockGuard guard{s().m_mutex}; + return s().v3errorStr(); } - static std::ostringstream& v3errorStr() { return s_errorStr; } - static void vlAbortOrExit(); static void vlAbort(); // static, but often overridden in classes. - static void v3errorEnd(std::ostringstream& sstr, const string& extra = ""); + static void v3errorEnd(std::ostringstream& sstr, const string& extra = "") + VL_MT_SAFE_EXCLUDES(s().m_mutex) VL_MT_SAFE { + const VerilatedLockGuard guard{s().m_mutex}; + s().v3errorEnd(sstr, extra); + } + // We can't call 's().v3errorEnd' directly in 'v3ErrorEnd'/'v3errorEndFatal', + // due to bug in GCC (tested on 11.3.0 version with --enable-m32) + // causing internal error when backtrace is printed. + // Instead use this wrapper. + static void v3errorEndGuardedCall(std::ostringstream& sstr, const string& extra = "") + VL_REQUIRES(s().m_mutex) VL_MT_SAFE { + s().v3errorEnd(sstr, extra); + } }; // Global versions, so that if the class doesn't define a operator, we get the functions anyways. -inline void v3errorEnd(std::ostringstream& sstr) { V3Error::v3errorEnd(sstr); } -inline void v3errorEndFatal(std::ostringstream& sstr) { - V3Error::v3errorEnd(sstr); +inline void v3errorEnd(std::ostringstream& sstr) VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE { + V3Error::v3errorEndGuardedCall(sstr); +} +inline void v3errorEndFatal(std::ostringstream& sstr) + VL_REQUIRES(V3Error::s().m_mutex) VL_MT_SAFE { + V3Error::v3errorEndGuardedCall(sstr); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; } +#ifndef V3ERROR_NO_GLOBAL_ +#define V3ErrorLockAndCheckStopRequested \ + V3Error::s().m_mutex.lockCheckStopRequest( \ + []() -> void { V3ThreadPool::s().waitIfStopRequested(); }) +#else +#define V3ErrorLockAndCheckStopRequested V3Error::s().m_mutex.lock() +#endif + // Theses allow errors using << operators: v3error("foo"<<"bar"); // Careful, you can't put () around msg, as you would in most macro definitions // Note the commas are the comma operator, not separating arguments. These are needed to ensure // evaluation order as otherwise we couldn't ensure v3errorPrep is called first. +// Note: due to limitations of clang thread-safety analysis, we can't use +// lock guard here, instead we are locking the mutex as first operation in temporary, +// but we are unlocking the mutex after function using comma operator. +// This way macros should also work when they are in 'if' stmt without '{}'. #define v3warnCode(code, msg) \ - v3errorEnd((V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr())) + v3errorEnd((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \ + (V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \ + V3Error::s().m_mutex.unlock() #define v3warnCodeFatal(code, msg) \ - v3errorEndFatal( \ - (V3Error::v3errorPrep(code), (V3Error::v3errorStr() << msg), V3Error::v3errorStr())) + v3errorEndFatal((V3ErrorLockAndCheckStopRequested, V3Error::s().v3errorPrep(code), \ + (V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \ + V3Error::s().m_mutex.unlock() #define v3warn(code, msg) v3warnCode(V3ErrorCode::code, msg) #define v3info(msg) v3warnCode(V3ErrorCode::EC_INFO, msg) #define v3error(msg) v3warnCode(V3ErrorCode::EC_ERROR, msg) @@ -365,8 +571,10 @@ inline void v3errorEndFatal(std::ostringstream& sstr) { __FILE__ << ":" << std::dec << __LINE__ << ": " << msg) // Use this when normal v3fatal is called in static method that overrides fileline. #define v3fatalStatic(msg) \ - (::v3errorEndFatal((V3Error::v3errorPrep(V3ErrorCode::EC_FATAL), \ - (V3Error::v3errorStr() << msg), V3Error::v3errorStr()))) + (::v3errorEndFatal((V3ErrorLockAndCheckStopRequested, \ + V3Error::s().v3errorPrep(V3ErrorCode::EC_FATAL), \ + (V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr()))), \ + V3Error::s().m_mutex.unlock() #define UINFO(level, stmsg) \ do { \ diff --git a/src/V3File.cpp b/src/V3File.cpp index af4fa9162..0921f7956 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -633,7 +633,7 @@ bool V3OutFormatter::tokenMatch(const char* cp, const char* cmp) { ++cmp; } if (*cmp) return false; - if (*cp && !isspace(*cp)) return false; + if (*cp && !std::isspace(*cp)) return false; return true; } @@ -659,7 +659,7 @@ int V3OutFormatter::endLevels(const char* strg) { int levels = m_indentLevel; { const char* cp = strg; - while (isspace(*cp)) ++cp; + while (std::isspace(*cp)) ++cp; switch (*cp) { case '\n': // Newlines.. No need for whitespace before it return 0; @@ -669,7 +669,7 @@ int V3OutFormatter::endLevels(const char* strg) { { // label/public/private: Deindent by 2 spaces const char* mp = cp; - for (; isalnum(*mp); ++mp) {} + for (; std::isalnum(*mp); ++mp) {} if (mp[0] == ':' && mp[1] != ':') return (levels - m_blockIndent / 2); } } @@ -708,7 +708,7 @@ void V3OutFormatter::puts(const char* strg) { bool equalsForBracket = false; // Looking for "= {" for (const char* cp = strg; *cp; ++cp) { putcNoTracking(*cp); - if (isalpha(*cp)) { + if (std::isalpha(*cp)) { if (wordstart && m_lang == LA_VERILOG && tokenNotStart(cp)) notstart = true; if (wordstart && m_lang == LA_VERILOG && !notstart && tokenStart(cp)) indentInc(); if (wordstart && m_lang == LA_VERILOG && tokenEnd(cp)) indentDec(); @@ -870,7 +870,7 @@ string V3OutFormatter::quoteNameControls(const string& namein, V3OutFormatter::L out += std::string{">"}; } else if (c == '&') { out += std::string{"&"}; - } else if (isprint(c)) { + } else if (std::isprint(c)) { out += c; } else { out += std::string{"&#"} + cvtToStr((unsigned int)(c & 0xff)) + ";"; @@ -887,7 +887,7 @@ string V3OutFormatter::quoteNameControls(const string& namein, V3OutFormatter::L out += "\\r"; } else if (c == '\t') { out += "\\t"; - } else if (isprint(c)) { + } else if (std::isprint(c)) { out += c; } else { // This will also cover \a etc @@ -942,7 +942,7 @@ void V3OutCFile::putsGuard() { string var = VString::upcase(std::string{"VERILATED_"} + V3Os::filenameNonDir(filename()) + "_"); for (char& c : var) { - if (!isalnum(c)) c = '_'; + if (!std::isalnum(c)) c = '_'; } puts("\n#ifndef " + var + "\n"); puts("#define " + var + " // guard\n"); diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 026bd2823..80c2d1a85 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -210,26 +210,26 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { // will come from the same stream as the previous line. // Skip `line - while (*textp && isspace(*textp)) textp++; - while (*textp && !isspace(*textp)) textp++; - while (*textp && (isspace(*textp) || *textp == '"')) textp++; + while (*textp && std::isspace(*textp)) ++textp; + while (*textp && !std::isspace(*textp)) ++textp; + while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp; // Grab linenumber bool fail = false; const char* const ln = textp; - while (*textp && !isspace(*textp)) textp++; - if (isdigit(*ln)) { + while (*textp && !std::isspace(*textp)) ++textp; + if (std::isdigit(*ln)) { lineno(std::atoi(ln)); } else { fail = true; } - while (*textp && (isspace(*textp))) textp++; + while (*textp && (std::isspace(*textp))) ++textp; if (*textp != '"') fail = true; - while (*textp && (isspace(*textp) || *textp == '"')) textp++; + while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp; // Grab filename const char* const fn = textp; - while (*textp && !(isspace(*textp) || *textp == '"')) textp++; + while (*textp && !(std::isspace(*textp) || *textp == '"')) ++textp; if (textp != fn) { string strfn = fn; strfn = strfn.substr(0, textp - fn); @@ -239,8 +239,8 @@ void FileLine::lineDirective(const char* textp, int& enterExitRef) { } // Grab level - while (*textp && (isspace(*textp) || *textp == '"')) textp++; - if (isdigit(*textp)) { + while (*textp && (std::isspace(*textp) || *textp == '"')) ++textp; + if (std::isdigit(*textp)) { enterExitRef = std::atoi(textp); if (enterExitRef >= 3) fail = true; } else { @@ -322,7 +322,7 @@ string FileLine::asciiLineCol() const { + "-" + cvtToStr(lastColumn()) + "[" + (m_contentp ? m_contentp->ascii() : "ct0") + "+" + cvtToStr(m_contentLineno) + "]"); } -string FileLine::ascii() const VL_MT_SAFE { +string FileLine::ascii() const { // For most errors especially in the parser the lastLineno is more accurate than firstLineno return filename() + ":" + cvtToStr(lastLineno()) + ":" + cvtToStr(firstColumn()); } @@ -369,7 +369,7 @@ void FileLine::warnUnusedOff(bool flag) { warnOff(V3ErrorCode::UNUSEDSIGNAL, flag); } -bool FileLine::warnIsOff(V3ErrorCode code) const VL_MT_SAFE { +bool FileLine::warnIsOff(V3ErrorCode code) const { if (!msgEn().test(code)) return true; if (!defaultFileLine().msgEn().test(code)) return true; // Global overrides local if ((code.lintError() || code.styleError()) && !msgEn().test(V3ErrorCode::I_LINT)) { @@ -380,7 +380,8 @@ bool FileLine::warnIsOff(V3ErrorCode code) const VL_MT_SAFE { } // cppverilator-suppress constParameter -void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) { +void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) + VL_REQUIRES(V3Error::s().m_mutex) { std::ostringstream nsstr; if (lastLineno()) nsstr << this; nsstr << sstr.str(); @@ -390,29 +391,33 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) { lstr << std::setw(ascii().length()) << " " << ": " << extra; } - m_waive = V3Config::waive(this, V3Error::errorCode(), sstr.str()); - if (warnIsOff(V3Error::errorCode()) || m_waive) { - V3Error::suppressThisWarning(); - } else if (!V3Error::errorContexted()) { + m_waive = V3Config::waive(this, V3Error::s().errorCode(), sstr.str()); + if (warnIsOff(V3Error::s().errorCode()) || m_waive) { + V3Error::s().suppressThisWarning(); + } else if (!V3Error::s().errorContexted()) { nsstr << warnContextPrimary(); } - if (!m_waive) V3Waiver::addEntry(V3Error::errorCode(), filename(), sstr.str()); - V3Error::v3errorEnd(nsstr, lstr.str()); + if (!m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str()); + V3Error::s().v3errorEnd(nsstr, lstr.str()); } -string FileLine::warnMore() const { +string FileLine::warnMore() const VL_REQUIRES(V3Error::s().m_mutex) { if (lastLineno()) { - return V3Error::warnMore() + string(ascii().size(), ' ') + ": "; + return V3Error::s().warnMore() + string(ascii().size(), ' ') + ": "; } else { - return V3Error::warnMore(); + return V3Error::s().warnMore(); } } -string FileLine::warnOther() const VL_MT_SAFE { +string FileLine::warnOther() const VL_REQUIRES(V3Error::s().m_mutex) { if (lastLineno()) { - return V3Error::warnMore() + ascii() + ": "; + return V3Error::s().warnMore() + ascii() + ": "; } else { - return V3Error::warnMore(); + return V3Error::s().warnMore(); } +}; +string FileLine::warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE { + const VerilatedLockGuard guard{V3Error::s().m_mutex}; + return warnOther(); } string FileLine::source() const VL_MT_SAFE { @@ -435,8 +440,7 @@ string FileLine::prettySource() const VL_MT_SAFE { return VString::spaceUnprintable(out); } -string FileLine::warnContext(bool secondary) const VL_MT_SAFE { - V3Error::errorContexted(true); +string FileLine::warnContext() const { if (!v3Global.opt.context()) return ""; string out; if (firstLineno() == lastLineno() && firstColumn()) { @@ -457,16 +461,18 @@ string FileLine::warnContext(bool secondary) const VL_MT_SAFE { out += "\n"; } } - if (!secondary) { // Avoid printing long paths on informational part of error - for (FileLine* parentFl = parent(); parentFl; parentFl = parentFl->parent()) { - if (parentFl->filenameIsGlobal()) break; - out += parentFl->warnOther() + "... note: In file included from " - + parentFl->filebasename() + "\n"; - } - } return out; } +string FileLine::warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex) { + string out; + for (FileLine* parentFl = parent(); parentFl; parentFl = parentFl->parent()) { + if (parentFl->filenameIsGlobal()) break; + out += parentFl->warnOther() + "... note: In file included from " + + parentFl->filebasename() + "\n"; + } + return out; +} #ifdef VL_LEAK_CHECKS std::unordered_set fileLineLeakChecks; diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 2da4cc73d..42c72f25b 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -261,6 +261,11 @@ public: // Turn on/off warning messages on this line. void warnOn(V3ErrorCode code, bool flag) { + if (code == V3ErrorCode::WIDTH) { + warnOn(V3ErrorCode::WIDTHTRUNC, flag); + warnOn(V3ErrorCode::WIDTHEXPAND, flag); + warnOn(V3ErrorCode::WIDTHXZEXPAND, flag); + } m_msgEnIdx = singleton().msgEnSetBit(m_msgEnIdx, code, flag); } void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); } @@ -309,24 +314,30 @@ public: void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code, flag); } // OPERATORS - void v3errorEnd(std::ostringstream& str, const string& extra = ""); - void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN { + void v3errorEnd(std::ostringstream& str, const string& extra = "") + VL_REQUIRES(V3Error::s().m_mutex); + void v3errorEndFatal(std::ostringstream& str) VL_ATTR_NORETURN + VL_REQUIRES(V3Error::s().m_mutex) { v3errorEnd(str); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; } /// When building an error, prefix for printing continuation lines /// e.g. information referring to the same FileLine as before - string warnMore() const; + string warnMore() const VL_REQUIRES(V3Error::s().m_mutex); /// When building an error, prefix for printing secondary information /// from a different FileLine than the original error - string warnOther() const VL_MT_SAFE; + string warnOther() const VL_REQUIRES(V3Error::s().m_mutex); + string warnOtherStandalone() const VL_EXCLUDES(V3Error::s().m_mutex) VL_MT_UNSAFE; /// When building an error, current location in include etc /// If not used in a given error, automatically pasted at end of error - string warnContextPrimary() const VL_MT_SAFE { return warnContext(false); } + string warnContextPrimary() const VL_REQUIRES(V3Error::s().m_mutex) { + V3Error::s().errorContexted(true); + return warnContext() + warnContextParent(); + } /// When building an error, additional location for additional references /// Simplified information vs warnContextPrimary() to make dump clearer - string warnContextSecondary() const VL_MT_SAFE { return warnContext(true); } + string warnContextSecondary() const { return warnContext(); } bool operator==(const FileLine& rhs) const { return (m_firstLineno == rhs.m_firstLineno && m_firstColumn == rhs.m_firstColumn && m_lastLineno == rhs.m_lastLineno && m_lastColumn == rhs.m_lastColumn @@ -349,7 +360,8 @@ public: } private: - string warnContext(bool secondary) const VL_MT_SAFE; + string warnContext() const; + string warnContextParent() const VL_REQUIRES(V3Error::s().m_mutex); const MsgEnBitSet& msgEn() const VL_MT_SAFE { return singleton().msgEn(m_msgEnIdx); } }; std::ostream& operator<<(std::ostream& os, FileLine* fileline); diff --git a/src/V3Force.cpp b/src/V3Force.cpp index 46a1166f7..1073f1c8c 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -55,21 +55,17 @@ class ForceConvertVisitor final : public VNVisitor { // TYPES struct ForceComponentsVar { AstVar* const m_rdVarp; // New variable to replace read references with - AstVar* const m_enVarp; // Force enabled signal AstVar* const m_valVarp; // Forced value - AstVar* const m_phVarp; // Placeholder variable for release (never read) + AstVar* const m_enVarp; // Force enabled signal explicit ForceComponentsVar(AstVar* varp) : m_rdVarp{new AstVar{varp->fileline(), VVarType::WIRE, varp->name() + "__VforceRd", varp->dtypep()}} - , m_enVarp{new AstVar{varp->fileline(), VVarType::VAR, varp->name() + "__VforceEn", - varp->dtypep()}} , m_valVarp{new AstVar{varp->fileline(), VVarType::VAR, varp->name() + "__VforceVal", varp->dtypep()}} - , m_phVarp{new AstVar{varp->fileline(), VVarType::VAR, varp->name() + "__VforcePh", - varp->dtypep()}} { + , m_enVarp{new AstVar{varp->fileline(), VVarType::VAR, varp->name() + "__VforceEn", + (isRangedDType(varp) ? varp->dtypep() : varp->findBitDType())}} { m_rdVarp->addNext(m_enVarp); m_rdVarp->addNext(m_valVarp); - m_rdVarp->addNext(m_phVarp); varp->addNextHere(m_rdVarp); if (varp->isPrimaryIO()) { @@ -87,15 +83,12 @@ class ForceConvertVisitor final : public VNVisitor { AstVarScope* const m_rdVscp; // New variable to replace read references with AstVarScope* const m_enVscp; // Force enabled signal AstVarScope* const m_valVscp; // Forced value - AstVarScope* const m_phVscp; // Placeholder variable for release (never read) explicit ForceComponentsVarScope(AstVarScope* vscp, ForceComponentsVar& fcv) : m_rdVscp{new AstVarScope{vscp->fileline(), vscp->scopep(), fcv.m_rdVarp}} , m_enVscp{new AstVarScope{vscp->fileline(), vscp->scopep(), fcv.m_enVarp}} - , m_valVscp{new AstVarScope{vscp->fileline(), vscp->scopep(), fcv.m_valVarp}} - , m_phVscp{new AstVarScope{vscp->fileline(), vscp->scopep(), fcv.m_phVarp}} { + , m_valVscp{new AstVarScope{vscp->fileline(), vscp->scopep(), fcv.m_valVarp}} { m_rdVscp->addNext(m_enVscp); m_rdVscp->addNext(m_valVscp); - m_rdVscp->addNext(m_phVscp); vscp->addNextHere(m_rdVscp); FileLine* const flp = vscp->fileline(); @@ -118,12 +111,20 @@ class ForceConvertVisitor final : public VNVisitor { AstVarRef* const lhsp = new AstVarRef{flp, m_rdVscp, VAccess::WRITE}; AstVarRef* const origp = new AstVarRef{flp, vscp, VAccess::READ}; origp->user2(1); // Don't replace this read ref with the read signal - AstOr* const rhsp = new AstOr{ - flp, - new AstAnd{flp, new AstVarRef{flp, m_enVscp, VAccess::READ}, - new AstVarRef{flp, m_valVscp, VAccess::READ}}, - new AstAnd{flp, new AstNot{flp, new AstVarRef{flp, m_enVscp, VAccess::READ}}, - origp}}; + AstNodeExpr* rhsp; + if (isRangedDType(vscp)) { + rhsp = new AstOr{ + flp, + new AstAnd{flp, new AstVarRef{flp, m_enVscp, VAccess::READ}, + new AstVarRef{flp, m_valVscp, VAccess::READ}}, + new AstAnd{flp, + new AstNot{flp, new AstVarRef{flp, m_enVscp, VAccess::READ}}, + origp}}; + } else { + rhsp = new AstCond{flp, new AstVarRef{flp, m_enVscp, VAccess::READ}, + new AstVarRef{flp, m_valVscp, VAccess::READ}, origp}; + } + AstActive* const activep = new AstActive{flp, "force-comb", new AstSenTree{flp, new AstSenItem{flp, AstSenItem::Combo{}}}}; @@ -144,6 +145,12 @@ class ForceConvertVisitor final : public VNVisitor { AstUser1Allocator m_forceComponentsVarScope; // METHODS + static bool isRangedDType(AstNode* nodep) { + // If ranged we need a multibit enable to support bit-by-bit part-select forces, + // otherwise forcing a real or other opaque dtype and need a single bit enable. + const AstBasicDType* const basicp = nodep->dtypep()->skipRefp()->basicp(); + return basicp && basicp->isRanged(); + } const ForceComponentsVarScope& getForceComponents(AstVarScope* vscp) { AstVar* const varp = vscp->varp(); return m_forceComponentsVarScope(vscp, vscp, m_forceComponentsVar(varp, varp)); @@ -178,7 +185,7 @@ class ForceConvertVisitor final : public VNVisitor { AstNodeExpr* const rhsp = nodep->rhsp(); // The value we are forcing it to // Set corresponding enable signals to ones - V3Number ones{lhsp, lhsp->width()}; + V3Number ones{lhsp, isRangedDType(lhsp) ? lhsp->width() : 1}; ones.setAllBits1(); AstAssign* const setEnp = new AstAssign{flp, lhsp->cloneTree(false), new AstConst{rhsp->fileline(), ones}}; @@ -213,7 +220,7 @@ class ForceConvertVisitor final : public VNVisitor { AstNodeExpr* const lhsp = nodep->lhsp(); // The LValue we are releasing // Set corresponding enable signals to zero - V3Number zero{lhsp, lhsp->width()}; + V3Number zero{lhsp, isRangedDType(lhsp) ? lhsp->width() : 1}; zero.setAllBits0(); AstAssign* const resetEnp = new AstAssign{flp, lhsp->cloneTree(false), new AstConst{lhsp->fileline(), zero}}; diff --git a/src/V3FunctionTraits.h b/src/V3FunctionTraits.h index 5f4e133a1..3fa0a7305 100644 --- a/src/V3FunctionTraits.h +++ b/src/V3FunctionTraits.h @@ -19,7 +19,7 @@ #include "verilatedos.h" -#include +#include #include #include diff --git a/src/V3Global.cpp b/src/V3Global.cpp index 89fac8f91..81f24ade4 100644 --- a/src/V3Global.cpp +++ b/src/V3Global.cpp @@ -53,6 +53,14 @@ void V3Global::readFiles() { V3ParseSym parseSyms{v3Global.rootp()}; // Symbol table must be common across all parsing V3Parse parser(v3Global.rootp(), &filter, &parseSyms); + + // Parse the std package + if (v3Global.opt.std()) { + parser.parseFile(new FileLine{V3Options::getStdPackagePath()}, + V3Options::getStdPackagePath(), false, + "Cannot find verilated_std.sv containing built-in std:: definitions:"); + } + // Read top module const V3StringList& vFiles = v3Global.opt.vFiles(); for (const string& filename : vFiles) { @@ -60,13 +68,6 @@ void V3Global::readFiles() { "Cannot find file containing module: "); } - if (usesStdPackage()) { - // Parse the std package - parser.parseFile(new FileLine{FileLine::commandLineFilename()}, - V3Options::getStdPackagePath(), false, - "Cannot find verilated_std.sv containing built-in std:: definitions:"); - } - // Read libraries // To be compatible with other simulators, // this needs to be done after the top file is read @@ -75,6 +76,15 @@ void V3Global::readFiles() { parser.parseFile(new FileLine{FileLine::commandLineFilename()}, filename, true, "Cannot find file containing library module: "); } + + // Delete the std package if unused + if (!usesStdPackage()) { + if (AstNodeModule* stdp = v3Global.rootp()->stdPackagep()) { + v3Global.rootp()->stdPackagep(nullptr); + VL_DO_DANGLING(stdp->unlinkFrBack()->deleteTree(), stdp); + } + } + // v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree")); V3Error::abortIfErrors(); diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index 202cd4587..27b37adf2 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -129,7 +129,7 @@ V3GraphEdge* V3GraphVertex::findConnectingEdgep(GraphWay way, const V3GraphVerte } // cppcheck-has-bug-suppress constParameter -void V3GraphVertex::v3errorEnd(std::ostringstream& str) const { +void V3GraphVertex::v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { std::ostringstream nsstr; nsstr << str.str(); if (debug()) { @@ -139,10 +139,11 @@ void V3GraphVertex::v3errorEnd(std::ostringstream& str) const { if (FileLine* const flp = fileline()) { flp->v3errorEnd(nsstr); } else { - V3Error::v3errorEnd(nsstr); + V3Error::s().v3errorEnd(nsstr); } } -void V3GraphVertex::v3errorEndFatal(std::ostringstream& str) const { +void V3GraphVertex::v3errorEndFatal(std::ostringstream& str) const + VL_REQUIRES(V3Error::s().m_mutex) { v3errorEnd(str); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; diff --git a/src/V3Graph.h b/src/V3Graph.h index 132221767..27aa13908 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -248,8 +248,8 @@ public: V3GraphEdge* beginp(GraphWay way) const { return way.forward() ? outBeginp() : inBeginp(); } // METHODS /// Error reporting - void v3errorEnd(std::ostringstream& str) const; - void v3errorEndFatal(std::ostringstream& str) const; + void v3errorEnd(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex); + void v3errorEndFatal(std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex); /// Edges are routed around this vertex to point from "from" directly to "to" void rerouteEdges(V3Graph* graphp); /// Find the edge connecting ap and bp, where bp is wayward from ap. diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 533fccd0e..78ea53c8f 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -343,7 +343,7 @@ private: // Arrayed instants: one bit for each of the instants (each // assign is 1 modwidth wide) if (m_cellRangep->littleEndian()) { - nodep->exprp()->v3warn(LITENDIAN, "Little endian instance range connecting to " + nodep->exprp()->v3warn(LITENDIAN, "Big endian instance range connecting to " "vector: left < right of instance range: [" << m_cellRangep->leftConst() << ":" << m_cellRangep->rightConst() << "]"); diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index f6db23721..20f5e545c 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -352,8 +352,10 @@ private: } // Convert .* to list of pins bool pinStar = false; + bool pinDotName = false; for (AstPin *nextp, *pinp = nodep->pinsp(); pinp; pinp = nextp) { nextp = VN_AS(pinp->nextp(), Pin); + if (pinp->svDotName()) pinDotName = true; if (pinp->dotStar()) { if (pinStar) pinp->v3error("Duplicate .* in an instance (IEEE 1800-2017 23.3.2)"); pinStar = true; @@ -374,8 +376,8 @@ private: // Note what pins exist std::unordered_set ports; // Symbol table of all connected port names for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_AS(pinp->nextp(), Pin)) { - if (pinStar && pinp->name().substr(0, 11) == "__pinNumber") { - pinp->v3error("Connect by position is illegal in .* connected instances" + if ((pinStar || pinDotName) && pinp->name().substr(0, 11) == "__pinNumber") { + pinp->v3error("Mixing positional and .*/named instantiation connection" " (IEEE 1800-2017 23.3.2)"); } if (!pinp->exprp()) { @@ -404,6 +406,7 @@ private: nodep->fileline(), 0, portp->name(), new AstParseRef{nodep->fileline(), VParseRefExp::PX_TEXT, portp->name(), nullptr, nullptr}}; + newp->svDotName(true); newp->svImplicit(true); nodep->addPinsp(newp); } else { // warn on the CELL that needs it, not the port diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index c87fd5198..db591012f 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -273,14 +273,16 @@ public: UINFO(4, "Var2 " << fnodep << endl); if (nodep->type() == fnodep->type()) { nodep->v3error("Duplicate declaration of " - << nodeTextType(fnodep) << ": " << nodep->prettyNameQ() << '\n' + << nodeTextType(fnodep) << ": " << AstNode::prettyNameQ(name) + << '\n' << nodep->warnContextPrimary() << '\n' << fnodep->warnOther() << "... Location of original declaration\n" << fnodep->warnContextSecondary()); } else { nodep->v3error("Unsupported in C: " << ucfirst(nodeTextType(nodep)) << " has the same name as " - << nodeTextType(fnodep) << ": " << nodep->prettyNameQ() << '\n' + << nodeTextType(fnodep) << ": " << AstNode::prettyNameQ(name) + << '\n' << nodep->warnContextPrimary() << '\n' << fnodep->warnOther() << "... Location of original declaration\n" << fnodep->warnContextSecondary()); @@ -1066,6 +1068,12 @@ class LinkDotFindVisitor final : public VNVisitor { VL_RESTORER(m_curSymp); VSymEnt* upSymp = m_curSymp; { + if (VN_IS(m_curSymp->nodep(), Class) + && VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->pureVirtual() + && !nodep->isConstructor()) { + nodep->v3error("Interface class functions must be pure virtual" + << " (IEEE 1800-2017 8.26): " << nodep->prettyNameQ()); + } // Change to appropriate package if extern declaration (vs definition) if (nodep->classOrPackagep()) { AstClassOrPackageRef* const cpackagerefp @@ -1135,11 +1143,23 @@ class LinkDotFindVisitor final : public VNVisitor { iterate(nodep->sensesp()); iterateAndNextNull(nodep->itemsp()); // If the block has no name, one cannot reference the clockvars - if (nodep->name().empty()) return; - VL_RESTORER(m_curSymp); - m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep); - m_curSymp->fallbackp(nullptr); - iterateAndNextNull(nodep->itemsp()); + VSymEnt* itSymp = nullptr; + if (nodep->isGlobal() // + && m_statep->forPrimary()) { // else flattening may see two globals + m_statep->checkDuplicate(m_curSymp, nodep, "__024global_clock"); + itSymp + = m_statep->insertBlock(m_curSymp, "__024global_clock", nodep, m_classOrPackagep); + itSymp->fallbackp(nullptr); + } + if (!nodep->name().empty()) { + itSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep); + itSymp->fallbackp(nullptr); + } + if (itSymp) { + VL_RESTORER(m_curSymp); + m_curSymp = itSymp; + iterateAndNextNull(nodep->itemsp()); + } } void visit(AstClockingItem* nodep) override { if (nodep->varp()) { @@ -1176,8 +1196,10 @@ class LinkDotFindVisitor final : public VNVisitor { // Var: Remember its name for later resolution UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Var not under module?"); iterateChildren(nodep); - if (nodep->isFuncLocal() && nodep->lifetime().isStatic()) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: 'static' function/task variables"); + if (VN_IS(m_curSymp->nodep(), Class) + && VN_AS(m_curSymp->nodep(), Class)->isInterfaceClass() && !nodep->isParam()) { + nodep->v3error("Interface class cannot contain non-parameter members" + << " (IEEE 1800-2017 8.26): " << nodep->prettyNameQ()); } if (!m_statep->forScopeCreation()) { // Find under either a task or the module's vars @@ -1373,8 +1395,11 @@ class LinkDotFindVisitor final : public VNVisitor { UINFO(4, " Link: " << nodep << endl); VSymEnt* const srcp = m_statep->getNodeSym(nodep->packagep()); if (nodep->name() == "*") { - if (m_curSymp == m_statep->dunitEntp()) { - nodep->v3warn(IMPORTSTAR, "Import::* in $unit scope may pollute global namespace"); + if (nodep->packagep() != v3Global.rootp()->stdPackagep()) { + if (m_curSymp == m_statep->dunitEntp()) { + nodep->v3warn(IMPORTSTAR, + "Import::* in $unit scope may pollute global namespace"); + } } } else { VSymEnt* const impp = srcp->findIdFlat(nodep->name()); @@ -1686,7 +1711,8 @@ private: } void visit(AstTypedefFwd* nodep) override { VSymEnt* const foundp = m_statep->getNodeSym(nodep)->findIdFallback(nodep->name()); - if (!foundp && v3Global.opt.pedantic()) { + if (!foundp && v3Global.opt.pedantic() + && nodep->name() != "process") { // Process is dangling as isn't implemented yet // We only check it was ever really defined in pedantic mode, as it // might have been in a header file referring to a module we never // needed so there are false positives @@ -1974,10 +2000,13 @@ private: // Cleared on global // *::user1p() -> See LinkDotState // *::user2p() -> See LinkDotState - // *::user3() // bool. Processed + // *::user3() // bool. Processed // *::user4() -> See LinkDotState // Cleared on Cell - // AstVar::user5() // bool. True if pin used in this cell + // AstVar::user5() // bool. True if pin used in this cell + // AstClass::user5() // bool. True if class has a parameter + // as a (possibly indirect) base class. + // Used only in LDS_PRIMARY pass const VNUser3InUse m_inuser3; const VNUser5InUse m_inuser5; @@ -2000,12 +2029,14 @@ private: AstNodeFTask* m_ftaskp = nullptr; // Current function/task int m_modportNum = 0; // Uniqueify modport numbers bool m_inSens = false; // True if in senitem + std::set m_ifClassImpNames; // Names imported from interface class struct DotStates { DotPosition m_dotPos; // Scope part of dotted resolution VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup const AstDot* m_dotp; // Current dot - bool m_unresolved; // Unresolved, needs help from V3Param + bool m_unresolvedCell; // Unresolved cell, needs help from V3Param + bool m_unresolvedClass; // Unresolved class reference, needs help from V3Param AstNode* m_unlinkedScopep; // Unresolved scope, needs corresponding VarXRef bool m_dotErr; // Error found in dotted resolution, ignore upwards string m_dotText; // String of dotted names found in below parseref @@ -2017,7 +2048,8 @@ private: m_dotp = nullptr; m_dotErr = false; m_dotText = ""; - m_unresolved = false; + m_unresolvedCell = false; + m_unresolvedClass = false; m_unlinkedScopep = nullptr; } string ascii() const { @@ -2026,7 +2058,8 @@ private: sstr << "ds=" << names[m_dotPos]; sstr << " dse" << cvtToHex(m_dotSymp); sstr << " txt=" << m_dotText; - sstr << " unr=" << m_unresolved; + sstr << " unrCell=" << m_unresolvedCell; + sstr << " unrClass=" << m_unresolvedClass; return sstr.str(); } } m_ds; // State to preserve across recursions @@ -2153,6 +2186,47 @@ private: } while (classSymp && !VN_IS(classSymp->nodep(), Class)); return classSymp; } + void importImplementsClass(AstClass* implementsClassp, VSymEnt* interfaceSymp, + AstClass* interfaceClassp) { + UINFO(8, "importImplementsClass to " << implementsClassp << " from " << interfaceClassp + << endl); + for (VSymEnt::const_iterator it = interfaceSymp->begin(); it != interfaceSymp->end(); + ++it) { + if (AstNode* interfaceSubp = it->second->nodep()) { + UINFO(8, " SymFunc " << interfaceSubp << endl); + if (VN_IS(interfaceSubp, NodeFTask)) { + const VSymEnt* const foundp = m_curSymp->findIdFlat(interfaceSubp->name()); + bool existsInChild = foundp && !foundp->imported(); + if (!existsInChild && !implementsClassp->isInterfaceClass()) { + implementsClassp->v3error( + "Class " << implementsClassp->prettyNameQ() << " implements " + << interfaceClassp->prettyNameQ() + << " but is missing implementation for " + << interfaceSubp->prettyNameQ() << " (IEEE 1800-2017 8.26)\n" + << implementsClassp->warnContextPrimary() << '\n' + << interfaceSubp->warnOther() + << "... Location of interface class's function\n" + << interfaceSubp->warnContextSecondary()); + } + if (!existsInChild + && m_ifClassImpNames.find(interfaceSubp->name()) + != m_ifClassImpNames.end()) { + implementsClassp->v3error( + "Class " << implementsClassp->prettyNameQ() << " implements " + << interfaceClassp->prettyNameQ() + << " but missing inheritance conflict resolution for " + << interfaceSubp->prettyNameQ() + << " (IEEE 1800-2017 8.26.6.2)\n" + << implementsClassp->warnContextPrimary() << '\n' + << interfaceSubp->warnOther() + << "... Location of interface class's function\n" + << interfaceSubp->warnContextSecondary()); + } + m_ifClassImpNames.emplace(interfaceSubp->name()); + } + } + } + } // VISITs void visit(AstNetlist* nodep) override { @@ -2340,14 +2414,12 @@ private: } if (m_statep->forPrimary() && isParamedClassRef(nodep->lhsp())) { // Dots of paramed classes will be linked after deparameterization - m_ds.m_dotPos = DP_NONE; - return; + m_ds.m_unresolvedClass = true; } - if (m_ds.m_unresolved + if (m_ds.m_unresolvedCell && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) { m_ds.m_unlinkedScopep = nodep->lhsp(); } - if (VN_IS(nodep->lhsp(), LambdaArgRef)) m_ds.m_unlinkedScopep = nodep->lhsp(); if (!m_ds.m_dotErr) { // Once something wrong, give up // Top 'final' dot RHS is final RHS, else it's a // DOT(DOT(x,*here*),real-rhs) which we consider a RHS @@ -2355,32 +2427,35 @@ private: iterateAndNextNull(nodep->rhsp()); // if (debug() >= 9) nodep->dumpTree("- dot-rho: "); } - if (start) { - AstNode* newp; - if (m_ds.m_dotErr) { - newp = new AstConst{nodep->fileline(), AstConst::BitFalse{}}; - } else { - // RHS is what we're left with - newp = nodep->rhsp()->unlinkFrBack(); + if (!m_ds.m_unresolvedClass) { + if (start) { + AstNode* newp; + if (m_ds.m_dotErr) { + newp = new AstConst{nodep->fileline(), AstConst::BitFalse{}}; + } else { + newp = nodep->rhsp()->unlinkFrBack(); + } + if (debug() >= 9) newp->dumpTree("- dot-out: "); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { // Dot midpoint + AstNodeExpr* newp = nodep->rhsp()->unlinkFrBack(); + if (m_ds.m_unresolvedCell) { + AstCellRef* const crp = new AstCellRef{ + nodep->fileline(), nodep->name(), nodep->lhsp()->unlinkFrBack(), newp}; + newp = crp; + } + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); } - if (debug() >= 9) newp->dumpTree("- dot-out: "); - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - } else { // Dot midpoint - AstNodeExpr* newp = nodep->rhsp()->unlinkFrBack(); - if (m_ds.m_unresolved) { - AstCellRef* const crp = new AstCellRef{nodep->fileline(), nodep->name(), - nodep->lhsp()->unlinkFrBack(), newp}; - newp = crp; - } - nodep->replaceWith(newp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); } } if (start) { m_ds = lastStates; } else { + const bool unresolvedClass = m_ds.m_unresolvedClass; m_ds.m_dotp = lastStates.m_dotp; + m_ds.m_unresolvedClass |= unresolvedClass; } } void visit(AstSenItem* nodep) override { @@ -2391,6 +2466,7 @@ private: void visit(AstParseRef* nodep) override { if (nodep->user3SetOnce()) return; UINFO(9, " linkPARSEREF " << m_ds.ascii() << " n=" << nodep << endl); + if (m_ds.m_unresolvedClass) return; // m_curSymp is symbol table of outer expression // m_ds.m_dotSymp is symbol table relative to "."'s above now UASSERT_OBJ(m_ds.m_dotSymp, nodep, "nullptr lookup symbol table"); @@ -2431,7 +2507,7 @@ private: // If not, treat it as normal member select iterateChildren(nodep); const auto newp = new AstLambdaArgRef{ - nodep->fileline(), m_ds.m_unlinkedScopep->name() + "__DOT__index", true}; + nodep->fileline(), m_ds.m_dotp->lhsp()->name() + "__DOT__index", true}; nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); return; @@ -2566,7 +2642,7 @@ private: varp->attrSplitVar(false); } m_ds.m_dotText = ""; - if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) { + if (m_ds.m_unresolvedCell && m_ds.m_unlinkedScopep) { const string dotted = refp->dotted(); const size_t pos = dotted.find("__BRA__??__KET__"); // Arrays of interfaces all have the same parameters @@ -2578,7 +2654,7 @@ private: newp = new AstUnlinkedRef{nodep->fileline(), refp, refp->name(), m_ds.m_unlinkedScopep->unlinkFrBack()}; m_ds.m_unlinkedScopep = nullptr; - m_ds.m_unresolved = false; + m_ds.m_unresolvedCell = false; } } else { newp = refp; @@ -2668,12 +2744,18 @@ private: } else if (VN_IS(foundp->nodep(), Clocking)) { m_ds.m_dotSymp = foundp; ok = m_ds.m_dotPos == DP_SCOPE; - } else if (VN_IS(foundp->nodep(), Property)) { - AstFuncRef* const propRefp - = new AstFuncRef{nodep->fileline(), nodep->name(), nullptr}; - nodep->replaceWith(propRefp); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - ok = m_ds.m_dotPos == DP_NONE; + } else if (const AstNodeFTask* const ftaskp = VN_CAST(foundp->nodep(), NodeFTask)) { + if (!ftaskp->isFunction()) { + ok = m_ds.m_dotPos == DP_NONE; + if (ok) { + // The condition is true for tasks, properties and void functions. + // In these cases, the parentheses may be skipped. + AstFuncRef* const funcRefp + = new AstFuncRef{nodep->fileline(), nodep->name(), nullptr}; + nodep->replaceWith(funcRefp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + } } // if (!ok) { @@ -2741,8 +2823,15 @@ private: UINFO(4, "(Backto) Link ClassOrPackageRef: " << nodep << endl); iterateChildren(nodep); } + if (m_statep->forPrimary() && VN_IS(nodep->classOrPackagep(), Class) && !nodep->paramsp() + && nodep->classOrPackagep()->hasGParam() + // Don't warn on typedefs, which are hard to know if there's a param somewhere buried + && VN_IS(nodep->classOrPackageNodep(), Class)) { + nodep->v3error("Reference to parameterized class without #() (IEEE 1800-2017 8.25.1)\n" + << nodep->warnMore() << "... Suggest use '" + << nodep->classOrPackageNodep()->prettyName() << "#()'"); + } } - void visit(AstVarRef* nodep) override { // VarRef: Resolve its reference // ParseRefs are used the first pass (forPrimary) so we shouldn't get can't find @@ -2876,12 +2965,32 @@ private: if (nodep->user3SetOnce()) return; UINFO(8, " " << nodep << endl); UINFO(8, " " << m_ds.ascii() << endl); - if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { + { + // Visit arguments at the beginning. + // They may be visitted even if the current node can't be linked now. + VL_RESTORER(m_ds); + m_ds.init(m_curSymp); + iterateChildren(nodep); + } + + if (m_ds.m_unresolvedClass) { + // Unable to link before V3Param + return; + } else if (m_ds.m_unresolvedCell && m_ds.m_dotPos == DP_FINAL && m_ds.m_unlinkedScopep) { + AstNodeFTaskRef* const newftaskp = nodep->cloneTree(false); + newftaskp->dotted(m_ds.m_dotText); + AstNode* const newp = new AstUnlinkedRef{nodep->fileline(), newftaskp, nodep->name(), + m_ds.m_unlinkedScopep->unlinkFrBack()}; + m_ds.m_unlinkedScopep = nullptr; + m_ds.m_unresolvedCell = false; + nodep->replaceWith(newp); + return; + } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); AstClassOrPackageRef* const cpackagerefp = VN_AS(m_ds.m_dotp->lhsp(), ClassOrPackageRef); - if (cpackagerefp->name() == "process" || cpackagerefp->name() == "local") { + if (cpackagerefp->name() == "local") { nodep->v3warn(E_UNSUPPORTED, "Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name())); } @@ -2890,19 +2999,7 @@ private: m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = nullptr; } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) { - if (m_ds.m_unresolved && m_ds.m_unlinkedScopep) { - AstNodeFTaskRef* const newftaskp = nodep->cloneTree(false); - newftaskp->dotted(m_ds.m_dotText); - AstNode* const newp - = new AstUnlinkedRef{nodep->fileline(), newftaskp, nodep->name(), - m_ds.m_unlinkedScopep->unlinkFrBack()}; - m_ds.m_unlinkedScopep = nullptr; - m_ds.m_unresolved = false; - nodep->replaceWith(newp); - return; - } else { - nodep->dotted(m_ds.m_dotText); // Maybe "" - } + nodep->dotted(m_ds.m_dotText); // Maybe "" } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) { // Found a Var, everything following is method call. // {scope}.{var}.HERE {method} ( ARGS ) @@ -3033,11 +3130,6 @@ private: } taskFuncSwapCheck(nodep); } - { - VL_RESTORER(m_ds); - m_ds.init(m_curSymp); - iterateChildren(nodep); - } } void visit(AstSelBit* nodep) override { if (nodep->user3SetOnce()) return; @@ -3046,7 +3138,7 @@ private: == DP_SCOPE) { // Already under dot, so this is {modulepart} DOT {modulepart} UINFO(9, " deferring until after a V3Param pass: " << nodep << endl); m_ds.m_dotText += "__BRA__??__KET__"; - m_ds.m_unresolved = true; + m_ds.m_unresolvedCell = true; // And pass up m_ds.m_dotText } // Pass dot state down to fromp() @@ -3059,7 +3151,7 @@ private: iterateAndNextNull(nodep->attrp()); } } - if (m_ds.m_unresolved && m_ds.m_dotPos == DP_SCOPE) { + if (m_ds.m_unresolvedCell && m_ds.m_dotPos == DP_SCOPE) { AstNodeExpr* const exprp = nodep->bitp()->unlinkFrBack(); AstCellArrayRef* const newp = new AstCellArrayRef{nodep->fileline(), nodep->fromp()->name(), exprp}; @@ -3152,20 +3244,31 @@ private: iterateChildren(nodep); } void visit(AstClass* nodep) override { + nodep->user3SetOnce(); UINFO(5, " " << nodep << endl); checkNoDot(nodep); VL_RESTORER(m_curSymp); VL_RESTORER(m_modSymp); + VL_RESTORER(m_ifClassImpNames); { m_ds.init(m_curSymp); // Until overridden by a SCOPE m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); m_modp = nodep; + int next = 0; for (AstNode* itemp = nodep->extendsp(); itemp; itemp = itemp->nextp()) { if (AstClassExtends* const cextp = VN_CAST(itemp, ClassExtends)) { // Replace abstract reference with hard pointer // Will need later resolution when deal with parameters + if (++next == 2 && !nodep->isInterfaceClass() && !cextp->isImplements()) { + cextp->v3error("Multiple inheritance illegal on non-interface classes" + " (IEEE 1800-2017 8.13)"); + } if (cextp->childDTypep() || cextp->dtypep()) continue; // Already converted + if (VN_IS(cextp->classOrPkgsp(), Dot)) { + itemp->v3warn(E_UNSUPPORTED, "Unsupported: Hierarchical class references"); + continue; + } AstClassOrPackageRef* const cpackagerefp = VN_CAST(cextp->classOrPkgsp(), ClassOrPackageRef); if (VL_UNCOVERABLE(!cpackagerefp)) { @@ -3173,36 +3276,87 @@ private: cextp->v3error("Attempting to extend using non-class"); // LCOV_EXCL_LINE } else { VSymEnt* const foundp = m_curSymp->findIdFallback(cpackagerefp->name()); - bool ok = false; if (foundp) { - if (AstClass* const classp = VN_CAST(foundp->nodep(), Class)) { + AstClassRefDType* classRefDtypep = nullptr; + AstClass* classp = VN_CAST(foundp->nodep(), Class); + if (classp) { + if (classp != nodep) { + // Case with recursive inheritance is handled later in this + // function + iterate(classp); + } + if (classp->user5()) { + // Has a parameter as its base class + nodep->user5(true); + return; + } + AstPin* paramsp = cpackagerefp->paramsp(); + if (paramsp) paramsp = paramsp->cloneTree(true); + classRefDtypep + = new AstClassRefDType{nodep->fileline(), classp, paramsp}; + } else if (AstParamTypeDType* const paramp + = VN_CAST(foundp->nodep(), ParamTypeDType)) { + if (m_statep->forPrimary()) { + // Extending has to be handled after V3Param.cpp, but the type + // reference has to be visited + iterate(paramp); + nodep->user5(true); + return; + } else { + AstNodeDType* const paramTypep = paramp->getChildDTypep(); + classRefDtypep + = VN_CAST(paramTypep->cloneTree(false), ClassRefDType); + if (!classRefDtypep) { + paramTypep->v3error( + "Attempting to extend using non-class"); + } else { + classp = classRefDtypep->classp(); + } + } + } else { + cextp->v3warn(E_UNSUPPORTED, + "Unsupported: " << foundp->nodep()->prettyTypeName() + << " in AstClassExtends"); + } + + if (classp) { UINFO(8, "Import to " << nodep << " from export class " << classp << endl); if (classp == nodep) { cextp->v3error("Attempting to extend class " << nodep->prettyNameQ() << " from itself"); + } else if (cextp->isImplements() && !classp->isInterfaceClass()) { + cextp->v3error( + "Attempting to implement from non-interface class " + << classp->prettyNameQ() << '\n' + << "... Suggest use 'extends'"); + } else if (!cextp->isImplements() && !nodep->isInterfaceClass() + && classp->isInterfaceClass()) { + cextp->v3error("Attempting to extend from interface class " + << classp->prettyNameQ() << '\n' + << "... Suggest use 'implements'"); } else { - AstPin* paramsp = cpackagerefp->paramsp(); - if (paramsp) paramsp = paramsp->cloneTree(true); - const auto newp - = new AstClassRefDType{nodep->fileline(), classp, paramsp}; - cextp->childDTypep(newp); + cextp->childDTypep(classRefDtypep); classp->isExtended(true); nodep->isExtended(true); VSymEnt* const srcp = m_statep->getNodeSym(classp); - m_curSymp->importFromClass(m_statep->symsp(), srcp); + if (classp->isInterfaceClass()) { + importImplementsClass(nodep, srcp, classp); + } + if (!cextp->isImplements()) { + m_curSymp->importFromClass(m_statep->symsp(), srcp); + } VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(), cpackagerefp); } - ok = true; } - } - if (!ok) { + } else { const string suggest = m_statep->suggestSymFallback( m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); cpackagerefp->v3error( - "Class to extend not found: " - << cpackagerefp->prettyNameQ() << '\n' + "Class for '" + << cextp->verilogKwd() // extends/implements + << "' not found: " << cpackagerefp->prettyNameQ() << '\n' << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); } } diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index fdd8dd70d..4a2bb0c1c 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -201,6 +201,15 @@ private: void prepost_stmt_visit(AstNodeTriop* nodep) { iterateChildren(nodep); + // Currently we can't reference the target, so we just copy the AST both for read and + // write, but doing so would double any side-effects, so as a safety measure all + // statements which could have side-effects are banned at the moment. + if (!nodep->rhsp()->isTreePureRecurse()) { + nodep->rhsp()->v3warn(E_UNSUPPORTED, + "Unsupported: Inc/Dec of expression with side-effects"); + return; + } + AstConst* const constp = VN_AS(nodep->lhsp(), Const); UASSERT_OBJ(nodep, constp, "Expecting CONST"); AstConst* const newconstp = constp->cloneTree(true); @@ -222,6 +231,15 @@ private: void prepost_expr_visit(AstNodeTriop* nodep) { iterateChildren(nodep); + // Currently we can't reference the target, so we just copy the AST both for read and + // write, but doing so would double any side-effects, so as a safety measure all + // statements which could have side-effects are banned at the moment. + if (!nodep->rhsp()->isTreePureRecurse()) { + nodep->rhsp()->v3warn(E_UNSUPPORTED, + "Unsupported: Inc/Dec of expression with side-effects"); + return; + } + const AstNodeVarRef* varrefp = nullptr; if (m_unsupportedHere || !(varrefp = VN_CAST(nodep->rhsp(), VarRef))) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Incrementation in this context."); diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index cfa121649..9718b9b67 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -59,15 +59,23 @@ void V3LinkLevel::modSortByLevel() { if (tops.size() >= 2) { const AstNode* const secp = tops[1]; // Complain about second one, as first often intended if (!secp->fileline()->warnIsOff(V3ErrorCode::MULTITOP)) { + auto warnTopModules = [](std::string warnMore, ModVec tops) + VL_REQUIRES(V3Error::s().m_mutex) -> std::string { + std::stringstream ss; + for (AstNode* alsop : tops) { + ss << warnMore << "... Top module " << alsop->prettyNameQ() << endl + << alsop->warnContextSecondary(); + } + return ss.str(); + }; + secp->v3warn(MULTITOP, "Multiple top level modules\n" << secp->warnMore() << "... Suggest see manual; fix the duplicates, or use " "--top-module to select top." - << V3Error::warnContextNone()); - for (AstNode* alsop : tops) { - std::cerr << secp->warnMore() << "... Top module " << alsop->prettyNameQ() << endl - << alsop->warnContextSecondary(); - } + << V3Error::s().warnContextNone() + << V3Error::warnAdditionalInfo() + << warnTopModules(secp->warnMore(), tops)); } } diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 8aa45b271..c0984fe98 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -148,8 +148,8 @@ private: if (classPkgRefp && VN_IS(classPkgRefp->classOrPackageNodep(), Class)) { // Class methods are automatic by default m_lifetime = VLifetime::AUTOMATIC; - } else if (nodep->dpiImport()) { - // DPI-imported function don't have lifetime specifiers + } else if (nodep->dpiImport() || VN_IS(nodep, Property)) { + // DPI-imported functions and properties don't have lifetime specifiers m_lifetime = VLifetime::NONE; } if (m_lifetime.isStatic() && hasStaticDeclAssignments(nodep)) { @@ -222,13 +222,10 @@ private: void visit(AstVar* nodep) override { cleanFileline(nodep); - if (nodep->lifetime().isNone()) { - if (m_ftaskp) { - nodep->lifetime(VLifetime::AUTOMATIC); - } else { - nodep->lifetime(m_lifetime); - } + if (nodep->lifetime().isNone() && nodep->varType() != VVarType::PORT) { + nodep->lifetime(m_lifetime); } + if (nodep->isGParam() && m_modp) m_modp->hasGParam(true); if (nodep->isParam() && !nodep->valuep() && nodep->fileline()->language() < V3LangCode::L1800_2009) { nodep->v3error("Parameter requires default value, or use IEEE 1800-2009 or later."); diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 6eb2a3897..6ecc90b2c 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -145,34 +145,13 @@ private: void visit(AstNodePreSel* nodep) override { if (!nodep->attrp()) { iterateChildren(nodep); - // Constification may change the fromp() to a constant, which will lose the - // variable we're extracting from (to determine MSB/LSB/endianness/etc.) - // So we replicate it in another node - // Note that V3Param knows not to replace AstVarRef's under AstAttrOf's AstNode* const basefromp = AstArraySel::baseFromp(nodep, false); - if (AstNodeVarRef* const varrefp - = VN_CAST(basefromp, NodeVarRef)) { // Maybe varxref - so need to clone - nodep->attrp(new AstAttrOf{nodep->fileline(), VAttrType::VAR_BASE, - varrefp->cloneTree(false)}); - } else if (AstUnlinkedRef* const uvxrp - = VN_CAST(basefromp, UnlinkedRef)) { // Maybe unlinked - so need to clone - nodep->attrp(new AstAttrOf{nodep->fileline(), VAttrType::VAR_BASE, - uvxrp->cloneTree(false)}); - } else if (auto* const fromp = VN_CAST(basefromp, LambdaArgRef)) { - nodep->attrp(new AstAttrOf{nodep->fileline(), VAttrType::VAR_BASE, - fromp->cloneTree(false)}); - } else if (AstMemberSel* const fromp = VN_CAST(basefromp, MemberSel)) { - nodep->attrp(new AstAttrOf{nodep->fileline(), VAttrType::MEMBER_BASE, - fromp->cloneTree(false)}); - } else if (AstEnumItemRef* const fromp = VN_CAST(basefromp, EnumItemRef)) { - nodep->attrp(new AstAttrOf{nodep->fileline(), VAttrType::ENUM_BASE, - fromp->cloneTree(false)}); - } else if (VN_IS(basefromp, Replicate)) { + if (VN_IS(basefromp, Replicate)) { // From {...}[...] syntax in IEEE 2017 if (basefromp) UINFO(1, " Related node: " << basefromp << endl); } else { - if (basefromp) UINFO(1, " Related node: " << basefromp << endl); - nodep->v3fatalSrc("Illegal bit select; no signal/member being extracted from"); + nodep->attrp(new AstAttrOf{nodep->fileline(), VAttrType::VAR_BASE, + basefromp->cloneTree(false)}); } } } @@ -233,12 +212,12 @@ private: inPct = true; inIgnore = false; fmt = ch; - } else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) { + } else if (inPct && (std::isdigit(ch) || ch == '.' || ch == '-')) { fmt += ch; } else if (inPct) { inPct = false; fmt += ch; - switch (tolower(ch)) { + switch (std::tolower(ch)) { case '%': // %% - just output a % break; case '*': diff --git a/src/V3Number.cpp b/src/V3Number.cpp index 30d58e482..b99717d60 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -76,7 +76,7 @@ constexpr int MAX_SPRINTF_DOUBLE_SIZE //====================================================================== // Errors -void V3Number::v3errorEnd(const std::ostringstream& str) const VL_MT_SAFE { +void V3Number::v3errorEnd(const std::ostringstream& str) const VL_REQUIRES(V3Error::s().m_mutex) { std::ostringstream nsstr; nsstr << str.str(); if (m_nodep) { @@ -84,11 +84,12 @@ void V3Number::v3errorEnd(const std::ostringstream& str) const VL_MT_SAFE { } else if (m_fileline) { m_fileline->v3errorEnd(nsstr); } else { - V3Error::v3errorEnd(nsstr); + V3Error::s().v3errorEnd(nsstr); } } -void V3Number::v3errorEndFatal(const std::ostringstream& str) const VL_MT_SAFE { +void V3Number::v3errorEndFatal(const std::ostringstream& str) const + VL_REQUIRES(V3Error::s().m_mutex) { v3errorEnd(str); assert(0); // LCOV_EXCL_LINE VL_UNREACHABLE; @@ -138,6 +139,7 @@ void V3Number::create(const char* sourcep) { } } + bool userSized = false; bool unbased = false; char base = '\0'; if (value_startp != sourcep) { // Has a ' @@ -151,7 +153,7 @@ void V3Number::create(const char* sourcep) { if (*cp != '_') widthn += *cp; } while (*cp == '_') cp++; - if (*cp && tolower(*cp) == 's') { + if (*cp && std::tolower(*cp) == 's') { cp++; isSigned(true); } @@ -161,6 +163,7 @@ void V3Number::create(const char* sourcep) { } value_startp = cp; + userSized = widthn.length() != 0; if (std::atoi(widthn.c_str())) { if (std::atoi(widthn.c_str()) < 0 || std::atoi(widthn.c_str()) > v3Global.opt.maxNumWidth()) { @@ -188,11 +191,11 @@ void V3Number::create(const char* sourcep) { width(1, false); // So we extend it setBit(0, 1); m_data.m_autoExtend = true; - } else if (tolower(base) == 'z') { + } else if (std::tolower(base) == 'z') { width(1, false); // So we extend it setBit(0, 'z'); m_data.m_autoExtend = true; - } else if (tolower(base) == 'x') { + } else if (std::tolower(base) == 'x') { width(1, false); // So we extend it setBit(0, 'x'); m_data.m_autoExtend = true; @@ -204,13 +207,17 @@ void V3Number::create(const char* sourcep) { } // Ignore leading blanks - while (*value_startp == '_' || isspace(*value_startp)) value_startp++; + while (*value_startp == '_' || std::isspace(*value_startp)) ++value_startp; if (!*value_startp && !m_data.m_autoExtend) { v3error("Number is missing value digits: " << sourcep); } + if (userSized && m_data.m_autoExtend) { + v3error("Syntax error: size cannot be provided with '0/'1/'x/'z: " + << sourcep << " (IEEE 1800-2017 5.7.1)"); + } int obit = 0; // Start at LSB - if (tolower(base) == 'd') { + if (std::tolower(base) == 'd') { // Ignore leading zeros so we don't issue too many digit errors when lots of leading 0's while (*value_startp == '_' || *value_startp == '0') value_startp++; // Convert decimal number to hex @@ -220,7 +227,7 @@ void V3Number::create(const char* sourcep) { int got_z = 0; int got_01 = 0; for (const char* cp = value_startp; *cp; cp++) { - switch (tolower(*cp)) { + switch (std::tolower(*cp)) { case '0': // FALLTHRU case '1': // FALLTHRU case '2': // FALLTHRU @@ -291,9 +298,9 @@ void V3Number::create(const char* sourcep) { v3error("Too many digits for " << width() << " bit number: " << sourcep); break; } - switch (tolower(base)) { + switch (std::tolower(base)) { case 'b': { - switch (tolower(*cp)) { + switch (std::tolower(*cp)) { case '0': setBit(obit++, 0); break; case '1': setBit(obit++, 1); break; case 'z': @@ -307,7 +314,7 @@ void V3Number::create(const char* sourcep) { case 'o': case 'c': { - switch (tolower(*cp)) { + switch (std::tolower(*cp)) { // clang-format off case '0': setBit(obit++, 0); setBit(obit++, 0); setBit(obit++, 0); break; case '1': setBit(obit++, 1); setBit(obit++, 0); setBit(obit++, 0); break; @@ -328,7 +335,7 @@ void V3Number::create(const char* sourcep) { } case 'h': { - switch (tolower(*cp)) { + switch (std::tolower(*cp)) { // clang-format off case '0': setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); break; case '1': setBit(obit++,1); setBit(obit++,0); setBit(obit++,0); setBit(obit++,0); break; @@ -568,7 +575,7 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const { bool V3Number::displayedFmtLegal(char format, bool isScan) { // Is this a valid format letter? - switch (tolower(format)) { + switch (std::tolower(format)) { case 'b': return true; case 'c': return true; case 'd': return true; // Unsigned decimal @@ -612,11 +619,11 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { ++pos; } string fmtsize; - for (; pos != vformat.cend() && (isdigit(pos[0]) || pos[0] == '.'); ++pos) { + for (; pos != vformat.cend() && (std::isdigit(pos[0]) || pos[0] == '.'); ++pos) { fmtsize += pos[0]; } string str; - const char code = tolower(pos[0]); + const char code = std::tolower(pos[0]); switch (code) { case 'b': // FALLTHRU case 'o': // FALLTHRU @@ -703,7 +710,8 @@ string V3Number::displayed(FileLine* fl, const string& vformat) const { return str; } // case b/d/x/o case 'c': { - if (width() > 8) fl->v3warn(WIDTH, "$display-like format of %c format of > 8 bit value"); + if (width() > 8) + fl->v3warn(WIDTHTRUNC, "$display-like format of %c format of > 8 bit value"); const unsigned int v = bitsValue(0, 8); char strc[2]; strc[0] = v & 0xff; @@ -1427,15 +1435,19 @@ V3Number& V3Number::opRepl(const V3Number& lhs, // i op repl, L(i)*value(rhs) bit return NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_LOGIC_ARGS1(lhs); - setZero(); - if (rhsval > 8192) { + if (rhsval > (1UL << 24)) { + v3error("More than a 16 Mbit replication, perhaps the replication factor" + " was two's-complement negative: " + << rhsval); + } else if (rhsval > 8192) { v3warn(WIDTHCONCAT, "More than a 8k bit replication is probably wrong: " << rhsval); } + setZero(); int obit = 0; - for (unsigned times = 0; times < rhsval; times++) { - for (int bit = 0; bit < lhs.width(); bit++) { + for (unsigned times = 0; times < rhsval; ++times) { + for (int bit = 0; bit < lhs.width(); ++bit) { setBit(obit, lhs.bitIs(bit)); - obit++; + ++obit; } } return *this; @@ -2194,13 +2206,13 @@ V3Number& V3Number::opAssignNonXZ(const V3Number& lhs, bool ignoreXZ) { m_data.m_isNull = true; } else if (isString()) { if (VL_UNLIKELY(!lhs.isString())) { - // Non-compatible types, erase value. - m_data.str() = ""; + // Numbers can still be strings + m_data.str() = lhs.toString(); } else { m_data.str() = lhs.m_data.str(); } } else if (VL_UNLIKELY(lhs.isString())) { - // Non-compatible types, erase value. + // Non-compatible types, see also opAToN() setZero(); } else { // Also handles double as is just bits @@ -2212,6 +2224,20 @@ V3Number& V3Number::opAssignNonXZ(const V3Number& lhs, bool ignoreXZ) { return *this; } +V3Number& V3Number::opNToI(const V3Number& lhs) { + // String to packed number + NUM_ASSERT_OP_ARGS1(lhs); + NUM_ASSERT_STRING_ARGS1(lhs); + setZero(); + const string& str = lhs.toString(); + for (size_t n = 0; n < str.length(); ++n) { + const char c = str[str.length() - 1 - n]; + for (size_t cbit = 0; cbit < 8; ++cbit) + setBit(n * 8 + cbit, VL_BITISSET_I(c, cbit) ? 1 : 0); + } + return *this; +} + V3Number& V3Number::opExtendS(const V3Number& lhs, uint32_t lbits) { // Note may be a width change during the sign extension NUM_ASSERT_OP_ARGS1(lhs); @@ -2243,7 +2269,8 @@ void V3Number::opCleanThis(bool warnOnTruncation) { const uint32_t newValueXMsb = v.m_valueX & hiWordMask(); if (warnOnTruncation && (newValueMsb != v.m_value || newValueXMsb != v.m_valueX)) { // Displaying in decimal avoids hiWordMask truncation - v3warn(WIDTH, "Value too large for " << width() << " bit number: " << displayed("%d")); + v3warn(WIDTHTRUNC, + "Value too large for " << width() << " bit number: " << displayed("%d")); } m_data.num()[words() - 1] = {newValueMsb, newValueXMsb}; } @@ -2459,15 +2486,13 @@ V3Number& V3Number::opReplN(const V3Number& lhs, uint32_t rhsval) { V3Number& V3Number::opToLowerN(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_STRING_ARGS1(lhs); - std::string out = lhs.toString(); - for (auto& cr : out) cr = tolower(cr); + std::string out = VString::downcase(lhs.toString()); return setString(out); } V3Number& V3Number::opToUpperN(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_STRING_ARGS1(lhs); - std::string out = lhs.toString(); - for (auto& cr : out) cr = toupper(cr); + std::string out = VString::upcase(lhs.toString()); return setString(out); } diff --git a/src/V3Number.h b/src/V3Number.h index b58806705..25b59706a 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -566,8 +566,9 @@ private: } public: - void v3errorEnd(const std::ostringstream& sstr) const; - void v3errorEndFatal(const std::ostringstream& sstr) const VL_ATTR_NORETURN; + void v3errorEnd(const std::ostringstream& sstr) const VL_REQUIRES(V3Error::s().m_mutex); + void v3errorEndFatal(const std::ostringstream& sstr) const VL_ATTR_NORETURN + VL_REQUIRES(V3Error::s().m_mutex); void width(int width, bool sized = true) { m_data.m_sized = sized; m_data.resize(width); @@ -761,6 +762,7 @@ public: // "N" - string operations V3Number& opAtoN(const V3Number& lhs, int base); + V3Number& opNToI(const V3Number& lhs); V3Number& opPutcN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths); V3Number& opGetcN(const V3Number& lhs, const V3Number& rhs); V3Number& opSubstrN(const V3Number& lhs, const V3Number& rhs, const V3Number& ths); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 2785a939b..faec6ba50 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -237,20 +237,20 @@ void VTimescale::parseSlashed(FileLine* fl, const char* textp, VTimescale& unitr precr = VTimescale::NONE; const char* cp = textp; - for (; isspace(*cp); ++cp) {} + for (; std::isspace(*cp); ++cp) {} const char* const unitp = cp; for (; *cp && *cp != '/'; ++cp) {} const string unitStr(unitp, cp - unitp); - for (; isspace(*cp); ++cp) {} + for (; std::isspace(*cp); ++cp) {} string precStr; if (*cp == '/') { ++cp; - for (; isspace(*cp); ++cp) {} + for (; std::isspace(*cp); ++cp) {} const char* const precp = cp; for (; *cp && *cp != '/'; ++cp) {} precStr = string(precp, cp - precp); } - for (; isspace(*cp); ++cp) {} + for (; std::isspace(*cp); ++cp) {} if (*cp) { fl->v3error("`timescale syntax error: '" << textp << "'"); return; @@ -489,8 +489,10 @@ string V3Options::fileExists(const string& filename) { std::set* setp = &(diriter->second); #ifdef _MSC_VER - for (const auto& dirEntry : std::filesystem::directory_iterator(dir.c_str())) - setp->insert(dirEntry.path().filename().string()); + try { + for (const auto& dirEntry : std::filesystem::directory_iterator(dir.c_str())) + setp->insert(dirEntry.path().filename().string()); + } catch (std::filesystem::filesystem_error const& ex) { return ""; } #else if (DIR* const dirp = opendir(dir.c_str())) { while (struct dirent* direntp = readdir(dirp)) setp->insert(direntp->d_name); @@ -570,26 +572,28 @@ string V3Options::filePath(FileLine* fl, const string& modname, const string& la void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { static bool shown_notfound_msg = false; if (modname.find("__Vhsh") != string::npos) { - std::cerr << V3Error::warnMore() << "... Unsupported: Name is longer than 127 characters;" + std::cerr << V3Error::warnMoreStandalone() + << "... Unsupported: Name is longer than 127 characters;" << " automatic file lookup not supported.\n"; - std::cerr << V3Error::warnMore() << "... Suggest putting filename with this module/package" + std::cerr << V3Error::warnMoreStandalone() + << "... Suggest putting filename with this module/package" << " onto command line instead.\n"; } else if (!shown_notfound_msg) { shown_notfound_msg = true; if (m_impp->m_incDirUsers.empty()) { fl->v3error("This may be because there's no search path specified with -I."); } - std::cerr << V3Error::warnMore() << "... Looked in:" << endl; + std::cerr << V3Error::warnMoreStandalone() << "... Looked in:" << endl; for (const string& dir : m_impp->m_incDirUsers) { for (const string& ext : m_impp->m_libExtVs) { const string fn = V3Os::filenameFromDirBase(dir, modname + ext); - std::cerr << V3Error::warnMore() << " " << fn << endl; + std::cerr << V3Error::warnMoreStandalone() << " " << fn << endl; } } for (const string& dir : m_impp->m_incDirFallbacks) { for (const string& ext : m_impp->m_libExtVs) { const string fn = V3Os::filenameFromDirBase(dir, modname + ext); - std::cerr << V3Error::warnMore() << " " << fn << endl; + std::cerr << V3Error::warnMoreStandalone() << " " << fn << endl; } } } @@ -602,7 +606,9 @@ void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { V3LangCode V3Options::fileLanguage(const string& filename) { string ext = V3Os::filenameNonDir(filename); string::size_type pos; - if ((pos = ext.rfind('.')) != string::npos) { + if (filename == V3Options::getStdPackagePath()) { + return V3LangCode::mostRecent(); + } else if ((pos = ext.rfind('.')) != string::npos) { ext.erase(0, pos + 1); const auto it = m_impp->m_langExts.find(ext); if (it != m_impp->m_langExts.end()) return it->second; @@ -770,15 +776,11 @@ void V3Options::notify() { FileLine* const cmdfl = new FileLine{FileLine::commandLineFilename()}; if (!outFormatOk() && v3Global.opt.main()) ccSet(); // --main implies --cc if not provided - if (!outFormatOk() && !cdc() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) { - v3fatal("verilator: Need --binary, --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, " + if (!outFormatOk() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) { + v3fatal("verilator: Need --binary, --cc, --sc, --dpi-hdr-only, --lint-only, " "--xml-only or --E option"); } - if (cdc()) { - cmdfl->v3warn(DEPRECATED, "Option --cdc is deprecated and is planned for removal"); - } - if (m_build && (m_gmake || m_cmake)) { cmdfl->v3error("--make cannot be used together with --build. Suggest see manual"); } @@ -820,16 +822,14 @@ void V3Options::notify() { // Default some options if not turned on or off if (v3Global.opt.skipIdentical().isDefault()) { v3Global.opt.m_skipIdentical.setTrueOrFalse( // - !v3Global.opt.cdc() // - && !v3Global.opt.dpiHdrOnly() // + !v3Global.opt.dpiHdrOnly() // && !v3Global.opt.lintOnly() // && !v3Global.opt.preprocOnly() // && !v3Global.opt.xmlOnly()); } if (v3Global.opt.makeDepend().isDefault()) { v3Global.opt.m_makeDepend.setTrueOrFalse( // - !v3Global.opt.cdc() // - && !v3Global.opt.dpiHdrOnly() // + !v3Global.opt.dpiHdrOnly() // && !v3Global.opt.lintOnly() // && !v3Global.opt.preprocOnly() // && !v3Global.opt.xmlOnly()); @@ -1079,7 +1079,6 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-CFLAGS", CbVal, callStrSetter(&V3Options::addCFlags)); DECL_OPTION("-cc", CbCall, [this]() { ccSet(); }); - DECL_OPTION("-cdc", OnOff, &m_cdc); DECL_OPTION("-clk", CbVal, callStrSetter(&V3Options::addClocker)); DECL_OPTION("-no-clk", CbVal, callStrSetter(&V3Options::addNoClocker)); DECL_OPTION("-comp-limit-blocks", Set, &m_compLimitBlocks).undocumented(); @@ -1145,7 +1144,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-dumpi-", CbPartialMatchVal, [this](const char* optp, const char* valp) { m_dumpLevel[optp] = std::atoi(valp); }); - DECL_OPTION("-E", Set, &m_preprocOnly); + DECL_OPTION("-E", CbOnOff, [this](bool flag) { + if (flag) m_std = false; + m_preprocOnly = flag; + }); DECL_OPTION("-error-limit", CbVal, static_cast(&V3Error::errorLimit)); DECL_OPTION("-exe", OnOff, &m_exe); DECL_OPTION("-expand-limit", CbVal, @@ -1286,8 +1288,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char fl->v3warn(DEPRECATED, "Option -O is deprecated. " "Use -f or -fno- instead."); for (const char* cp = optp; *cp; ++cp) { - const bool flag = isupper(*cp); - switch (tolower(*cp)) { + const bool flag = std::isupper(*cp); + switch (std::tolower(*cp)) { case '0': optimize(0); break; case '1': optimize(1); break; case '2': optimize(2); break; @@ -1405,6 +1407,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char m_statsVars = flag; m_stats |= flag; }); + DECL_OPTION("-std", OnOff, &m_std); DECL_OPTION("-structs-packed", OnOff, &m_structsPacked); DECL_OPTION("-sv", CbCall, [this]() { m_defaultLanguage = V3LangCode::L1800_2017; }); @@ -1505,6 +1508,17 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-v", CbVal, [this, &optdir](const char* valp) { V3Options::addLibraryFile(parseFileArg(optdir, valp)); }); + DECL_OPTION("-verilate-jobs", CbVal, [this, fl](const char* valp) { + int val = std::atoi(valp); + if (val < 0) { + fl->v3error("--verilate-jobs requires a non-negative integer, but '" + << valp << "' was passed"); + val = 1; + } else if (val == 0) { + val = std::thread::hardware_concurrency(); + } + m_verilateJobs = val; + }); DECL_OPTION("-verilate", OnOff, &m_verilate); DECL_OPTION("-version", CbCall, [this]() { showVersion(false); @@ -1512,7 +1526,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char }); DECL_OPTION("-vpi", OnOff, &m_vpi); - DECL_OPTION("-Wpedantic", OnOff, &m_pedantic); + DECL_OPTION("-Wpedantic", CbCall, [this]() { + m_pedantic = true; + V3Error::pretendError(V3ErrorCode::ASSIGNIN, false); + }); DECL_OPTION("-Wall", CbCall, []() { FileLine::globalWarnLintOff(false); FileLine::globalWarnStyleOff(false); @@ -1553,6 +1570,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char }); DECL_OPTION("-Wno-style", CbCall, []() { FileLine::globalWarnStyleOff(true); }); DECL_OPTION("-Wno-UNUSED", CbCall, []() { FileLine::globalWarnUnusedOff(true); }); + DECL_OPTION("-Wno-WIDTH", CbCall, []() { FileLine::globalWarnOff(V3ErrorCode::WIDTH, true); }); DECL_OPTION("-Wwarn-", CbPartialMatch, [this, fl, &parser](const char* optp) { const V3ErrorCode code{optp}; if (code == V3ErrorCode::EC_ERROR) { @@ -1574,6 +1592,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char V3Error::pretendError(V3ErrorCode::UNUSEDSIGNAL, false); V3Error::pretendError(V3ErrorCode::UNUSEDPARAM, false); }); + DECL_OPTION("-Wwarn-WIDTH", CbCall, []() { + FileLine::globalWarnOff(V3ErrorCode::WIDTH, false); + V3Error::pretendError(V3ErrorCode::WIDTH, false); + }); DECL_OPTION("-waiver-output", Set, &m_waiverOutput); DECL_OPTION("-x-assign", CbVal, [this, fl](const char* valp) { @@ -1622,12 +1644,13 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char || !std::strcmp(argv[i], "--j")) { // Allow gnu -- switches ++i; int val = 0; - if (i < argc && isdigit(argv[i][0])) { - val = atoi(argv[i]); // Can't be negative due to isdigit above + if (i < argc && std::isdigit(argv[i][0])) { + val = std::atoi(argv[i]); // Can't be negative due to isdigit above if (val == 0) val = std::thread::hardware_concurrency(); ++i; } if (m_buildJobs == -1) m_buildJobs = val; + if (m_verilateJobs == -1) m_verilateJobs = val; } else if (argv[i][0] == '-' || argv[i][0] == '+') { const char* argvNoDashp = (argv[i][1] == '-') ? (argv[i] + 2) : (argv[i] + 1); if (const int consumed = parser.parse(i, argc, argv)) { @@ -1660,6 +1683,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } } if (m_buildJobs == -1) m_buildJobs = 1; + if (m_verilateJobs == -1) m_verilateJobs = 1; } //====================================================================== @@ -1690,7 +1714,8 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { ++pos; } } else if (*pos == '/' && *(pos + 1) == '/' - && (pos == line.begin() || isspace(lastch))) { // But allow /file//path + && (pos == line.begin() + || std::isspace(lastch))) { // But allow /file//path break; // Ignore to EOL } else if (*pos == '#' && space_begin) { // Only # at [spaced] begin of line break; // Ignore to EOL @@ -1700,7 +1725,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { // cppcheck-suppress StlMissingComparison ++pos; } else { - if (!isspace(*pos)) space_begin = false; + if (!std::isspace(*pos)) space_begin = false; oline += *pos; } } @@ -1733,7 +1758,7 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename, bool rel) { char curr_char = whole_file[pos]; switch (st) { case ST_IN_OPTION: // Get all chars up to a white space or a "=" - if (isspace(curr_char)) { // End of option + if (std::isspace(curr_char)) { // End of option if (!arg.empty()) { // End of word args.push_back(arg); } diff --git a/src/V3Options.h b/src/V3Options.h index 27e4f5036..aa681b3ea 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -224,7 +224,6 @@ private: bool m_bboxSys = false; // main switch: --bbox-sys bool m_bboxUnsup = false; // main switch: --bbox-unsup bool m_build = false; // main switch: --build - bool m_cdc = false; // main switch: --cdc bool m_cmake = false; // main switch: --make cmake bool m_context = true; // main switch: --Wcontext bool m_coverageLine = false; // main switch: --coverage-block @@ -267,6 +266,7 @@ private: bool m_relativeIncludes = false; // main switch: --relative-includes bool m_reportUnoptflat = false; // main switch: --report-unoptflat bool m_savable = false; // main switch: --savable + bool m_std = true; // main switch: --std bool m_structsPacked = false; // main switch: --structs-packed bool m_systemC = false; // main switch: --sc: System C instead of simple C++ bool m_stats = false; // main switch: --stats @@ -317,6 +317,7 @@ private: int m_traceThreads = 0; // main switch: --trace-threads int m_unrollCount = 64; // main switch: --unroll-count int m_unrollStmts = 30000; // main switch: --unroll-stmts + int m_verilateJobs = -1; // main switch: --verilate-jobs int m_compLimitBlocks = 0; // compiler selection; number of nested blocks int m_compLimitMembers = 64; // compiler selection; number of members in struct before make anon array @@ -430,6 +431,7 @@ public: bool savable() const VL_MT_SAFE { return m_savable; } bool stats() const { return m_stats; } bool statsVars() const { return m_statsVars; } + bool std() const { return m_std; } bool structsPacked() const { return m_structsPacked; } bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined bool autoflush() const { return m_autoflush; } @@ -438,7 +440,6 @@ public: bool build() const { return m_build; } string buildDepBin() const { return m_buildDepBin; } void buildDepBin(const string& flag) { m_buildDepBin = flag; } - bool cdc() const { return m_cdc; } bool cmake() const { return m_cmake; } bool context() const VL_MT_SAFE { return m_context; } bool coverage() const VL_MT_SAFE { @@ -544,6 +545,7 @@ public: } int unrollCount() const { return m_unrollCount; } int unrollStmts() const { return m_unrollStmts; } + int verilateJobs() const { return m_verilateJobs; } int compLimitBlocks() const { return m_compLimitBlocks; } int compLimitMembers() const { return m_compLimitMembers; } diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 01dcfe8d3..a18dd6c2f 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -173,7 +173,7 @@ string V3Os::filenameSubstitute(const string& filename) { string::size_type endpos = pos + 1; while (((endpos + 1) < filename.length()) && (((brackets == NONE) - && (isalnum(filename[endpos + 1]) || filename[endpos + 1] == '_')) + && (std::isalnum(filename[endpos + 1]) || filename[endpos + 1] == '_')) || ((brackets == CURLY) && (filename[endpos + 1] != '}')) || ((brackets == PAREN) && (filename[endpos + 1] != ')')))) ++endpos; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index f5abe2e29..287968268 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -547,7 +547,10 @@ class ParamProcessor final { AstClass* const newClassp) { if (AstClassRefDType* const classRefp = VN_CAST(nodep, ClassRefDType)) { if (classRefp->classp() == oldClassp) classRefp->classp(newClassp); + } else if (AstClassOrPackageRef* const classRefp = VN_CAST(nodep, ClassOrPackageRef)) { + if (classRefp->classOrPackagep() == oldClassp) classRefp->classOrPackagep(newClassp); } + if (nodep->op1p()) replaceRefsRecurse(nodep->op1p(), oldClassp, newClassp); if (nodep->op2p()) replaceRefsRecurse(nodep->op2p(), oldClassp, newClassp); if (nodep->op3p()) replaceRefsRecurse(nodep->op3p(), oldClassp, newClassp); @@ -820,12 +823,18 @@ class ParamProcessor final { } for (auto* stmtp = srcModpr->stmtsp(); stmtp; stmtp = stmtp->nextp()) { - if (auto* dtypep = VN_CAST(stmtp, ParamTypeDType)) { + if (AstParamTypeDType* dtypep = VN_CAST(stmtp, ParamTypeDType)) { if (VN_IS(dtypep->subDTypep(), VoidDType)) { nodep->v3error("Missing type parameter: " << dtypep->prettyNameQ()); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } } + if (AstVar* const varp = VN_CAST(stmtp, Var)) { + if (VN_IS(srcModpr, Class) && varp->isParam() && !varp->valuep()) { + nodep->v3error("Class parameter without initial value is never given value" + << " (IEEE 1800-2017 6.20.1): " << varp->prettyNameQ()); + } + } } // Delete the parameters from the cell; they're not relevant any longer. @@ -911,6 +920,8 @@ class ParamVisitor final : public VNVisitor { bool m_iterateModule = false; // Iterating module body string m_generateHierName; // Generate portion of hierarchy name string m_unlinkedTxt; // Text for AstUnlinkedRef + AstNodeModule* m_modp; // Module iterating + std::vector m_dots; // Dot references to process std::multimap m_cellps; // Cells left to process (in current module) std::multimap m_workQueue; // Modules left to process @@ -940,7 +951,11 @@ class ParamVisitor final : public VNVisitor { if (modp->someInstanceName().empty()) modp->someInstanceName(modp->origName()); // Iterate the body - iterateChildren(modp); + { + VL_RESTORER(m_modp); + m_modp = modp; + iterateChildren(modp); + } // Process interface cells, then non-interface cells, which may reference an interface // cell. @@ -1007,6 +1022,21 @@ class ParamVisitor final : public VNVisitor { m_cellps.emplace(!isIface, nodep); } + // RHSs of AstDots need a relink when LHS is a parametrized class reference + void relinkDots() { + for (AstDot* const dotp : m_dots) { + const AstClassOrPackageRef* const classRefp = VN_AS(dotp->lhsp(), ClassOrPackageRef); + const AstClass* const lhsClassp = VN_AS(classRefp->classOrPackageNodep(), Class); + AstClassOrPackageRef* const rhsp = VN_AS(dotp->rhsp(), ClassOrPackageRef); + for (auto* itemp = lhsClassp->membersp(); itemp; itemp = itemp->nextp()) { + if (itemp->name() == rhsp->name()) { + rhsp->classOrPackageNodep(itemp); + break; + } + } + } + } + // VISITORS void visit(AstNodeModule* nodep) override { if (nodep->recursiveClone()) nodep->dead(true); // Fake, made for recursive elimination @@ -1037,7 +1067,7 @@ class ParamVisitor final : public VNVisitor { if (nodep->user5SetOnce()) return; // Process once iterateChildren(nodep); if (nodep->isParam()) { - if (!nodep->valuep()) { + if (!nodep->valuep() && !VN_IS(m_modp, Class)) { nodep->v3error("Parameter without initial value is never given value" << " (IEEE 1800-2017 6.20.1): " << nodep->prettyNameQ()); } else { @@ -1113,6 +1143,25 @@ class ParamVisitor final : public VNVisitor { nodep->varp(nullptr); // Needs relink, as may remove pointed-to var } + void visit(AstDot* nodep) override { + iterate(nodep->lhsp()); + // Check if it is a reference to a field of a parameterized class. + // If so, the RHS should be updated, when the LHS is replaced + // by a class with actual parameter values. + const AstClass* lhsClassp = nullptr; + const AstClassOrPackageRef* const classRefp = VN_CAST(nodep->lhsp(), ClassOrPackageRef); + if (classRefp) lhsClassp = VN_CAST(classRefp->classOrPackageNodep(), Class); + AstNode* rhsDefp = nullptr; + AstClassOrPackageRef* const rhsp = VN_CAST(nodep->rhsp(), ClassOrPackageRef); + if (rhsp) rhsDefp = rhsp->classOrPackageNodep(); + if (lhsClassp && rhsDefp) { + m_dots.push_back(nodep); + // No need to iterate into rhsp, because there should be nothing to do + } else { + iterate(nodep->rhsp()); + } + } + void visit(AstUnlinkedRef* nodep) override { AstVarXRef* const varxrefp = VN_CAST(nodep->refp(), VarXRef); AstNodeFTaskRef* const taskrefp = VN_CAST(nodep->refp(), NodeFTaskRef); @@ -1215,6 +1264,7 @@ class ParamVisitor final : public VNVisitor { } void visit(AstGenCase* nodep) override { UINFO(9, " GENCASE " << nodep << endl); + bool hit = false; AstNode* keepp = nullptr; iterateAndNextNull(nodep->exprp()); V3Case::caseLint(nodep); @@ -1240,7 +1290,10 @@ class ParamVisitor final : public VNVisitor { if (const AstConst* const ccondp = VN_CAST(ep, Const)) { V3Number match{nodep, 1}; match.opEq(ccondp->num(), exprp->num()); - if (!keepp && match.isNeqZero()) keepp = itemp->stmtsp(); + if (!hit && match.isNeqZero()) { + hit = true; + keepp = itemp->stmtsp(); + } } else { itemp->v3error("Generate Case item does not evaluate to constant"); } @@ -1251,7 +1304,10 @@ class ParamVisitor final : public VNVisitor { for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp = VN_AS(itemp->nextp(), CaseItem)) { if (itemp->isDefault()) { - if (!keepp) keepp = itemp->stmtsp(); + if (!hit) { + hit = true; + keepp = itemp->stmtsp(); + } } } // Replace @@ -1273,6 +1329,8 @@ public: // Relies on modules already being in top-down-order iterate(netlistp); + relinkDots(); + // Re-sort module list to be in topological order and fix-up incorrect levels. We need to // do this globally at the end due to the presence of recursive modules, which might be // expanded in orders that reuse earlier specializations later at a lower level. diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index d59129982..b60e6bb07 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -240,6 +240,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, const string& name, } else { nodep->trace(allTracingOn(nodep->fileline())); } + if (nodep->varType().isVPIAccessible()) { nodep->addAttrsp(GRAMMARP->cloneScopedSigAttr()); } // Remember the last variable created, so we can attach attributes to it in later parsing GRAMMARP->m_varAttrp = nodep; @@ -256,7 +257,7 @@ string V3ParseGrammar::deQuote(FileLine* fileline, string text) { int octal_digits = 0; for (string::const_iterator cp = text.begin(); cp != text.end(); ++cp) { if (quoted) { - if (isdigit(*cp)) { + if (std::isdigit(*cp)) { octal_val = octal_val * 8 + (*cp - '0'); if (++octal_digits == 3) { octal_digits = 0; @@ -285,13 +286,13 @@ string V3ParseGrammar::deQuote(FileLine* fileline, string text) { newtext += '\t'; } else if (*cp == 'v') { newtext += '\v'; // SystemVerilog 3.1 - } else if (*cp == 'x' && isxdigit(cp[1]) - && isxdigit(cp[2])) { // SystemVerilog 3.1 -#define vl_decodexdigit(c) ((isdigit(c) ? ((c) - '0') : (tolower((c)) - 'a' + 10))) + } else if (*cp == 'x' && std::isxdigit(cp[1]) + && std::isxdigit(cp[2])) { // SystemVerilog 3.1 +#define vl_decodexdigit(c) ((std::isdigit(c) ? ((c) - '0') : (std::tolower((c)) - 'a' + 10))) newtext += static_cast(16 * vl_decodexdigit(cp[1]) + vl_decodexdigit(cp[2])); cp += 2; - } else if (isalnum(*cp)) { + } else if (std::isalnum(*cp)) { fileline->v3error("Unknown escape sequence: \\" << *cp); break; } else { diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp index a9fb2bb92..b310beb96 100644 --- a/src/V3ParseImp.cpp +++ b/src/V3ParseImp.cpp @@ -134,10 +134,10 @@ void V3ParseImp::lexVerilatorCmtLintRestore(FileLine* fl) { void V3ParseImp::lexVerilatorCmtLint(FileLine* fl, const char* textp, bool warnOff) { const char* sp = textp; - while (*sp && !isspace(*sp)) ++sp; - while (*sp && isspace(*sp)) ++sp; - while (*sp && !isspace(*sp)) ++sp; - while (*sp && isspace(*sp)) ++sp; + while (*sp && !std::isspace(*sp)) ++sp; + while (*sp && std::isspace(*sp)) ++sp; + while (*sp && !std::isspace(*sp)) ++sp; + while (*sp && std::isspace(*sp)) ++sp; string msg = sp; string::size_type pos; if ((pos = msg.find('*')) != string::npos) msg.erase(pos); @@ -155,9 +155,9 @@ void V3ParseImp::lexVerilatorCmtBad(FileLine* fl, const char* textp) { if (cmtparse.substr(0, std::strlen("/*verilator")) == "/*verilator") { cmtparse.replace(0, std::strlen("/*verilator"), ""); } - while (isspace(cmtparse[0])) cmtparse.replace(0, 1, ""); + while (std::isspace(cmtparse[0])) cmtparse.replace(0, 1, ""); string cmtname; - for (int i = 0; isalnum(cmtparse[i]); i++) { cmtname += cmtparse[i]; } + for (int i = 0; std::isalnum(cmtparse[i]); i++) cmtname += cmtparse[i]; if (!v3Global.opt.isFuture(cmtname)) { fl->v3error("Unknown verilator comment: '" << textp << "'"); } @@ -191,7 +191,7 @@ double V3ParseImp::lexParseTimenum(const char* textp) { char* const strgp = new char[length + 1]; char* dp = strgp; const char* sp = textp; - for (; isdigit(*sp) || *sp == '_' || *sp == '.'; ++sp) { + for (; std::isdigit(*sp) || *sp == '_' || *sp == '.'; ++sp) { if (*sp != '_') *dp++ = *sp; } *dp++ = '\0'; @@ -256,7 +256,7 @@ void V3ParseImp::preprocDumps(std::ostream& os) { if (noblanks) { bool blank = true; for (string::iterator its = buf.begin(); its != buf.end(); ++its) { - if (!isspace(*its) && *its != '\n') { + if (!std::isspace(*its) && *its != '\n') { blank = false; break; } @@ -374,6 +374,32 @@ size_t V3ParseImp::tokenPipeScanParam(size_t depth) { return depth; } +size_t V3ParseImp::tokenPipeScanType(size_t depth) { + // Search around IEEE type_reference to see if is expression + // Return location of following token, or input if not found + // yTYPE__ETC '(' ... ')' ['==' '===' '!=' '!==='] + if (tokenPeekp(depth)->token != '(') return depth; + depth += 1; // Past the ( + int parens = 1; // Count first ( + while (true) { + const int tok = tokenPeekp(depth)->token; + if (tok == 0) { + UINFO(9, "tokenPipeScanType hit EOF; probably syntax error to come"); + break; + } else if (tok == '(') { + ++parens; + } else if (tok == ')') { + --parens; + if (parens == 0) { + ++depth; + break; + } + } + ++depth; + } + return depth; +} + void V3ParseImp::tokenPipeline() { // called from bison's "yylex", has a "this" if (m_tokensAhead.empty()) tokenPull(); // corrupts yylval @@ -388,6 +414,7 @@ void V3ParseImp::tokenPipeline() { || token == yLOCAL__LEX // || token == yNEW__LEX // || token == ySTATIC__LEX // + || token == yTYPE__LEX // || token == yVIRTUAL__LEX // || token == yWITH__LEX // || token == yaID__LEX // @@ -443,6 +470,18 @@ void V3ParseImp::tokenPipeline() { } else { token = ySTATIC__ETC; } + } else if (token == yTYPE__LEX) { + VL_RESTORER(yylval); // Remember value, as about to read ahead + const size_t depth = tokenPipeScanType(0); + const int postToken = tokenPeekp(depth)->token; + if ( // v-- token v-- postToken + // yTYPE__EQ '(' .... ')' EQ_OPERATOR yTYPE_ETC '(' ... ')' + postToken == yP_EQUAL || postToken == yP_NOTEQUAL || postToken == yP_CASEEQUAL + || postToken == yP_CASENOTEQUAL) { + token = yTYPE__EQ; + } else { + token = yTYPE__ETC; + } } else if (token == yVIRTUAL__LEX) { if (nexttok == yCLASS) { token = yVIRTUAL__CLASS; @@ -496,7 +535,7 @@ void V3ParseImp::tokenPipelineSym() { if (const VSymEnt* const look_underp = V3ParseImp::parsep()->symp()->nextId()) { UINFO(7, " tokenPipelineSym: next id lookup forced under " << look_underp << endl); // if (debug() >= 7) V3ParseImp::parsep()->symp()->dumpSelf(cout, " -symtree: "); - foundp = look_underp->findIdFallback(*(yylval.strp)); + foundp = look_underp->findIdFlat(*(yylval.strp)); // "consume" it. Must set again if want another token under temp scope V3ParseImp::parsep()->symp()->nextId(nullptr); } else { @@ -507,6 +546,19 @@ void V3ParseImp::tokenPipelineSym() { // " -findtree: ", true); foundp = V3ParseImp::parsep()->symp()->symCurrentp()->findIdFallback(*(yylval.strp)); } + if (!foundp && !m_afterColonColon) { // Check if the symbol can be found in std + AstPackage* const stdpkgp = v3Global.rootp()->stdPackagep(); + if (stdpkgp) { + VSymEnt* const stdsymp = stdpkgp->user4u().toSymEnt(); + foundp = stdsymp->findIdFallback(*(yylval.strp)); + } + if (foundp && !v3Global.usesStdPackage()) { + AstPackageImport* const impp + = new AstPackageImport(stdpkgp->fileline(), stdpkgp, "*"); + unitPackage(stdpkgp->fileline())->addStmtsp(impp); + v3Global.setUsesStdPackage(); + } + } if (foundp) { AstNode* const scp = foundp->nodep(); yylval.scp = scp; @@ -523,20 +575,13 @@ void V3ParseImp::tokenPipelineSym() { } else { token = yaID__ETC; } + } else if (!m_afterColonColon && *(yylval.strp) == "std") { + v3Global.setUsesStdPackage(); } - } else if ((token == yaID__LEX || token == yaID__CC) - && (*(yylval.strp) == "mailbox" // IEEE-standard class - || *(yylval.strp) == "process" // IEEE-standard class - || *(yylval.strp) == "semaphore")) { // IEEE-standard class - v3Global.setUsesStdPackage(); - yylval.scp = nullptr; - if (token == yaID__LEX) token = yaID__aTYPE; } else { // Not found yylval.scp = nullptr; if (token == yaID__CC) { - if (!m_afterColonColon && *(yylval.strp) == "std") { - v3Global.setUsesStdPackage(); - } else if (!v3Global.opt.bboxUnsup()) { + if (!v3Global.opt.bboxUnsup()) { // IEEE does require this, but we may relax this as UVM breaks it, so allow // bbox for today // We'll get a parser error eventually but might not be obvious diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 14db28acc..e1037b130 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -303,6 +303,7 @@ private: void tokenPipeline(); // Internal; called from tokenToBison void tokenPipelineSym(); size_t tokenPipeScanParam(size_t depth); + size_t tokenPipeScanType(size_t depth); const V3ParseBisonYYSType* tokenPeekp(size_t depth); void preprocDumps(std::ostream& os); }; diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 32384386a..f59b5d1d3 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -185,7 +185,9 @@ public: // For getline() string m_lineChars; ///< Characters left for next line - void v3errorEnd(std::ostringstream& str) { fileline()->v3errorEnd(str); } + void v3errorEnd(std::ostringstream& str) VL_REQUIRES(V3Error::s().m_mutex) { + fileline()->v3errorEnd(str); + } static const char* tokenName(int tok); void debugToken(int tok, const char* cmtp); @@ -387,14 +389,14 @@ string V3PreProcImp::commentCleanup(const string& text) { while ((pos = cmd.find('\"')) != string::npos) cmd.replace(pos, 1, " "); while ((pos = cmd.find('\t')) != string::npos) cmd.replace(pos, 1, " "); while ((pos = cmd.find(" ")) != string::npos) cmd.replace(pos, 2, " "); - while (!cmd.empty() && isspace(cmd[cmd.size() - 1])) cmd.erase(cmd.size() - 1); + while (!cmd.empty() && std::isspace(cmd[cmd.size() - 1])) cmd.erase(cmd.size() - 1); return cmd; } bool V3PreProcImp::commentTokenMatch(string& cmdr, const char* strg) { int len = std::strlen(strg); - if (VString::startsWith(cmdr, strg) && (cmdr[len] == '\0' || isspace(cmdr[len]))) { - if (isspace(cmdr[len])) len++; + if (VString::startsWith(cmdr, strg) && (cmdr[len] == '\0' || std::isspace(cmdr[len]))) { + if (std::isspace(cmdr[len])) len++; cmdr = cmdr.substr(len); return true; } else { @@ -417,7 +419,7 @@ void V3PreProcImp::comment(const string& text) { return; } - while (isspace(*cp)) cp++; + while (std::isspace(*cp)) ++cp; bool synth = false; bool vlcomment = false; @@ -450,7 +452,7 @@ void V3PreProcImp::comment(const string& text) { if (!vlcomment && !synth) return; // Short-circuit - while (isspace(*cp)) cp++; + while (std::isspace(*cp)) ++cp; string cmd = commentCleanup(string(cp)); // cmd now is comment without extra spaces and "verilator" prefix @@ -472,12 +474,16 @@ void V3PreProcImp::comment(const string& text) { // else ignore the comment we don't recognize } // else no assertions } else if (vlcomment) { - string::size_type pos; - if ((pos = cmd.find("public_flat_rw")) != string::npos) { + if (VString::startsWith(cmd, "public_flat_rw")) { // "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)" - cmd = cmd.substr(pos + std::strlen("public_flat_rw")); - while (isspace(cmd[0])) cmd = cmd.substr(1); - if (!printed) insertUnreadback("/*verilator public_flat_rw*/ " + cmd + " /**/"); + string::size_type endOfCmd = std::strlen("public_flat_rw"); + while (VString::isWordChar(cmd[endOfCmd])) ++endOfCmd; + string baseCmd = cmd.substr(0, endOfCmd); + string arg = cmd.substr(endOfCmd); + while (std::isspace(arg[0])) arg = arg.substr(1); + if (arg.size() && baseCmd == "public_flat_rw_on") + baseCmd += "_sns"; // different cmd for applying sensitivity + if (!printed) insertUnreadback("/*verilator " + baseCmd + "*/ " + arg + " /**/"); } else { if (!printed) insertUnreadback("/*verilator " + cmd + "*/"); } @@ -554,16 +560,16 @@ string V3PreProcImp::trimWhitespace(const string& strg, bool trailing) { // Remove leading whitespace string out = strg; string::size_type leadspace = 0; - while (out.length() > leadspace && isspace(out[leadspace])) leadspace++; + while (out.length() > leadspace && std::isspace(out[leadspace])) ++leadspace; if (leadspace) out.erase(0, leadspace); // Remove trailing whitespace if (trailing) { string::size_type trailspace = 0; - while (out.length() > trailspace && isspace(out[out.length() - 1 - trailspace])) - trailspace++; + while (out.length() > trailspace && std::isspace(out[out.length() - 1 - trailspace])) + ++trailspace; // Don't remove \{space_or_newline} if (trailspace && out.length() > trailspace && out[out.length() - 1 - trailspace] == '\\') - trailspace--; + --trailspace; if (trailspace) out.erase(out.length() - trailspace, trailspace); } return out; @@ -675,13 +681,13 @@ string V3PreProcImp::defineSubst(VDefineRef* refp) { // UINFO(4, "CH "<<*cp<<" an "<(vtxp)) { AstNode* const logicp = lvtxp->logicp(); - std::cerr << logicp->fileline()->warnOther() + std::cerr << logicp->fileline()->warnOtherStandalone() << " Example path: " << logicp->typeName() << endl; } else { VarVertex* const vvtxp = dynamic_cast(vtxp); UASSERT(vvtxp, "Cannot be anything else"); AstVarScope* const vscp = vvtxp->vscp(); - std::cerr << vscp->fileline()->warnOther() + std::cerr << vscp->fileline()->warnOtherStandalone() << " Example path: " << vscp->prettyName() << endl; } } @@ -289,7 +289,7 @@ void reportLoopVars(Graph* graphp, VarVertex* vvtxp) { if (i == candidates.size()) break; const Candidate& candidate = candidates[i]; AstVar* const varp = candidate.first->varp(); - std::cerr << V3Error::warnMore() << " " << varp->fileline() << " " + std::cerr << V3Error::warnMoreStandalone() << " " << varp->fileline() << " " << varp->prettyName() << ", width " << std::dec << varp->width() << ", circular fanout " << candidate.second; if (V3SplitVar::canSplitVar(varp)) { @@ -301,19 +301,19 @@ void reportLoopVars(Graph* graphp, VarVertex* vvtxp) { }; // Widest variables - std::cerr << V3Error::warnMore() << "... Widest variables candidate to splitting:\n"; + std::cerr << V3Error::warnMoreStandalone() << "... Widest variables candidate to splitting:\n"; reportFirst10([](const Candidate& a, const Candidate& b) { return a.first->varp()->width() > b.first->varp()->width(); }); // Highest fanout - std::cerr << V3Error::warnMore() << "... Candidates with the highest fanout:\n"; + std::cerr << V3Error::warnMoreStandalone() << "... Candidates with the highest fanout:\n"; reportFirst10([](const Candidate& a, const Candidate& b) { // return a.second > b.second; }); if (splittable) { - std::cerr << V3Error::warnMore() + std::cerr << V3Error::warnMoreStandalone() << "... Suggest add /*verilator split_var*/ to appropriate variables above." << std::endl; } diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 0fda5bec2..7668b453d 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -122,7 +122,7 @@ private: if (AstRefDType* const refdtypep = VN_CAST(dtypep, RefDType)) { // dtypep = refdtypep->skipRefp(); } - if (AstStructDType* const stp = VN_CAST(dtypep, StructDType)) { + if (AstNodeUOrStructDType* const stp = VN_CAST(dtypep, NodeUOrStructDType)) { if (stp->packed()) { std::ostringstream out; out << "'{"; @@ -418,7 +418,7 @@ private: if (!VN_IS(nodep->varp()->dtypeSkipRefp(), BasicDType) && !VN_IS(nodep->varp()->dtypeSkipRefp(), PackArrayDType) && !VN_IS(nodep->varp()->dtypeSkipRefp(), UnpackArrayDType) - && !VN_IS(nodep->varp()->dtypeSkipRefp(), StructDType)) + && !VN_IS(nodep->varp()->dtypeSkipRefp(), NodeUOrStructDType)) clearOptimizable(nodep, "Array references/not basic"); if (nodep->access().isWriteOrRW()) { if (m_inDlyAssign) { @@ -442,7 +442,8 @@ private: clearOptimizable(nodep, "Var write & read"); } vscp->user1(vscp->user1() | VU_RV); - const bool isConst = nodep->varp()->isParam() && nodep->varp()->valuep(); + const bool isConst = (nodep->varp()->isConst() || nodep->varp()->isParam()) + && nodep->varp()->valuep(); AstNodeExpr* const valuep = isConst ? fetchValueNull(nodep->varp()->valuep()) : nullptr; // Propagate PARAM constants for constant function analysis @@ -503,6 +504,15 @@ private: checkNodeInfo(nodep); iterateChildren(nodep); } + void visit(AstInitialStatic* nodep) override { + if (jumpingOver(nodep)) return; + if (!m_params) { + badNodeType(nodep); + return; + } + checkNodeInfo(nodep); + iterateChildren(nodep); + } void visit(AstNodeIf* nodep) override { if (jumpingOver(nodep)) return; UINFO(5, " IF " << nodep << endl); @@ -1074,15 +1084,22 @@ private: const string format = nodep->text(); auto pos = format.cbegin(); bool inPct = false; + string width; for (; pos != format.cend(); ++pos) { if (!inPct && pos[0] == '%') { inPct = true; + width = ""; } else if (!inPct) { // Normal text result += *pos; } else { // Format character + if (std::isdigit(pos[0])) { + width += pos[0]; + continue; + } + inPct = false; - if (V3Number::displayedFmtLegal(tolower(pos[0]), false)) { + if (V3Number::displayedFmtLegal(std::tolower(pos[0]), false)) { AstNode* const argp = nextArgp; nextArgp = nextArgp->nextp(); AstConst* const constp = fetchConstNull(argp); @@ -1091,10 +1108,10 @@ private: nodep, "Argument for $display like statement is not constant"); break; } - const string pformat = std::string{"%"} + pos[0]; + const string pformat = std::string{"%"} + width + pos[0]; result += constp->num().displayed(nodep, pformat); } else { - switch (tolower(pos[0])) { + switch (std::tolower(pos[0])) { case '%': result += "%"; break; case 'm': // This happens prior to AstScope so we don't diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 8bee2d842..17ad58852 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -58,6 +58,7 @@ class SliceVisitor final : public VNVisitor { // STATE AstNode* m_assignp = nullptr; // Assignment we are under bool m_assignError = false; // True if the current assign already has an error + bool m_okInitArray = false; // Allow InitArray children // METHODS AstNodeExpr* cloneAndSel(AstNode* nodep, int elements, int offset) { @@ -163,8 +164,14 @@ class SliceVisitor final : public VNVisitor { } } + void visit(AstConsPackUOrStruct* nodep) override { + VL_RESTORER(m_okInitArray); + m_okInitArray = true; + iterateChildren(nodep); + } void visit(AstInitArray* nodep) override { - UASSERT_OBJ(!m_assignp, nodep, "Array initialization should have been removed earlier"); + UASSERT_OBJ(!m_assignp || m_okInitArray, nodep, + "Array initialization should have been removed earlier"); } void expandBiOp(AstNodeBiop* nodep) { diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp index 72123b2df..d72f13c1c 100644 --- a/src/V3StatsReport.cpp +++ b/src/V3StatsReport.cpp @@ -47,6 +47,7 @@ class StatsReport final { os << " " << V3Options::version() << '\n'; os << " Arguments: " << v3Global.opt.allArgsString() << '\n'; os << " Build jobs: " << v3Global.opt.buildJobs() << '\n'; + os << " Verilate jobs: " << v3Global.opt.verilateJobs() << '\n'; os << '\n'; } diff --git a/src/V3String.cpp b/src/V3String.cpp index 3db19a40c..f0aa6ecc8 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -80,13 +80,13 @@ string VString::dot(const string& a, const string& dot, const string& b) { string VString::downcase(const string& str) { string out = str; - for (auto& cr : out) cr = tolower(cr); + for (auto& cr : out) cr = std::tolower(cr); return out; } string VString::upcase(const string& str) { string out = str; - for (auto& cr : out) cr = toupper(cr); + for (auto& cr : out) cr = std::toupper(cr); return out; } @@ -133,7 +133,7 @@ string VString::escapeStringForPath(const string& str) { string VString::spaceUnprintable(const string& str) { string out; for (const char c : str) { - if (isprint(c)) { + if (std::isprint(c)) { out += c; } else { out += ' '; @@ -146,14 +146,14 @@ string VString::removeWhitespace(const string& str) { string out; out.reserve(str.size()); for (const char c : str) { - if (!isspace(c)) out += c; + if (!std::isspace(c)) out += c; } return out; } bool VString::isWhitespace(const string& str) { for (const char c : str) { - if (!isspace(c)) return false; + if (!std::isspace(c)) return false; } return true; } @@ -176,16 +176,14 @@ double VString::parseDouble(const string& str, bool* successp) { return d; } -static bool isWordChar(char c) { return isalnum(c) || c == '_'; } - string VString::replaceWord(const string& str, const string& from, const string& to) { string result = str; const size_t len = from.size(); UASSERT_STATIC(len > 0, "Cannot replace empty string"); for (size_t pos = 0; (pos = result.find(from, pos)) != string::npos; pos += len) { // Only replace whole words - if (((pos > 0) && isWordChar(result[pos - 1])) || // - ((pos + len < result.size()) && isWordChar(result[pos + len]))) { + if (((pos > 0) && VString::isWordChar(result[pos - 1])) || // + ((pos + len < result.size()) && VString::isWordChar(result[pos + len]))) { continue; } result.replace(pos, len, to); diff --git a/src/V3String.h b/src/V3String.h index d65c9db55..bbd3ba948 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -70,7 +70,7 @@ inline uint32_t cvtToHash(const void* vp) { inline string ucfirst(const string& text) { string out = text; - out[0] = toupper(out[0]); + out[0] = std::toupper(out[0]); return out; } @@ -122,6 +122,8 @@ public: static bool startsWith(const string& str, const string& prefix); // Predicate to check if 'str' ends with 'suffix' static bool endsWith(const string& str, const string& suffix); + // Return true if char is valid character in word + static bool isWordChar(char c) { return isalnum(c) || c == '_'; } }; //###################################################################### diff --git a/src/V3SymTable.h b/src/V3SymTable.h index d81b0f276..9d723a15e 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -266,7 +266,7 @@ public: } } if (scopes == "") scopes = ""; - std::cerr << V3Error::warnMore() << "... Known scopes under '" << prettyName + std::cerr << V3Error::warnMoreStandalone() << "... Known scopes under '" << prettyName << "': " << scopes << endl; if (debug()) dumpSelf(std::cerr, " KnownScope: ", 1); } diff --git a/src/V3ThreadPool.cpp b/src/V3ThreadPool.cpp new file mode 100644 index 000000000..6f4ba5ed6 --- /dev/null +++ b/src/V3ThreadPool.cpp @@ -0,0 +1,198 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Thread pool for Verilator itself +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2005-2023 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include "config_build.h" + +#include "V3ThreadPool.h" + +#include "V3Error.h" + +// c++11 requires definition of static constexpr as well as declaration +constexpr unsigned int V3ThreadPool::FUTUREWAITFOR_MS; + +void V3ThreadPool::resize(unsigned n) VL_MT_UNSAFE { + // This function is not thread-safe and can result in race between threads + VerilatedLockGuard lock{m_mutex}; + VerilatedLockGuard stoppedJobsLock{m_stoppedJobsMutex}; + UASSERT(m_queue.empty(), "Resizing busy thread pool"); + // Shut down old threads + m_shutdown = true; + m_stoppedJobs = 0; + m_cv.notify_all(); + m_stoppedJobsCV.notify_all(); + stoppedJobsLock.unlock(); + lock.unlock(); + while (!m_workers.empty()) { + m_workers.front().join(); + m_workers.pop_front(); + } + lock.lock(); + // Start new threads + m_shutdown = false; + for (unsigned int i = 1; i < n; ++i) { + m_workers.emplace_back(&V3ThreadPool::startWorker, this, i); + } +} + +void V3ThreadPool::startWorker(V3ThreadPool* selfThreadp, int id) VL_MT_SAFE { + selfThreadp->workerJobLoop(id); +} + +void V3ThreadPool::workerJobLoop(int id) VL_MT_SAFE { + while (true) { + // Wait for a notification + waitIfStopRequested(); + job_t job; + { + VerilatedLockGuard lock(m_mutex); + m_cv.wait(lock, [&]() VL_REQUIRES(m_mutex) { + return !m_queue.empty() || m_shutdown || m_stopRequested; + }); + if (m_shutdown) return; // Terminate if requested + if (stopRequestedStandalone()) { continue; } + // Get the job + UASSERT(!m_queue.empty(), "Job should be available"); + + job = m_queue.front(); + m_queue.pop(); + } + + // Execute the job + job(); + } +} + +template <> +void V3ThreadPool::pushJob(std::shared_ptr>& prom, + std::function&& f) VL_MT_SAFE { + if (willExecuteSynchronously()) { + f(); + prom->set_value(); + } else { + const VerilatedLockGuard lock{m_mutex}; + m_queue.push([prom, f] { + f(); + prom->set_value(); + }); + } +} + +void V3ThreadPool::requestExclusiveAccess(const V3ThreadPool::job_t&& exclusiveAccessJob) + VL_MT_SAFE { + if (willExecuteSynchronously()) { + exclusiveAccessJob(); + } else { + VerilatedLockGuard stoppedJobLock{m_stoppedJobsMutex}; + // if some other job already requested exclusive access + // wait until it stops + if (stopRequested()) { waitStopRequested(stoppedJobLock); } + m_stopRequested = true; + waitOtherThreads(stoppedJobLock); + m_exclusiveAccess = true; + exclusiveAccessJob(); + m_exclusiveAccess = false; + m_stopRequested = false; + m_stoppedJobsCV.notify_all(); + } +} + +bool V3ThreadPool::waitIfStopRequested() VL_MT_SAFE { + VerilatedLockGuard stoppedJobLock(m_stoppedJobsMutex); + if (!stopRequested()) return false; + waitStopRequested(stoppedJobLock); + return true; +} + +void V3ThreadPool::waitStopRequested(VerilatedLockGuard& stoppedJobLock) + VL_REQUIRES(m_stoppedJobsMutex) { + ++m_stoppedJobs; + m_stoppedJobsCV.notify_all(); + m_stoppedJobsCV.wait( + stoppedJobLock, [&]() VL_REQUIRES(m_stoppedJobsMutex) { return !m_stopRequested.load(); }); + --m_stoppedJobs; + m_stoppedJobsCV.notify_all(); +} + +void V3ThreadPool::waitOtherThreads(VerilatedLockGuard& stoppedJobLock) + VL_MT_SAFE_EXCLUDES(m_mutex) VL_REQUIRES(m_stoppedJobsMutex) { + ++m_stoppedJobs; + m_stoppedJobsCV.notify_all(); + m_cv.notify_all(); + m_stoppedJobsCV.wait(stoppedJobLock, [&]() VL_REQUIRES(m_stoppedJobsMutex) { + // count also the main thread + return m_stoppedJobs == (m_workers.size() + 1); + }); + --m_stoppedJobs; +} + +void V3ThreadPool::selfTest() { + VerilatedMutex commonMutex; + int commonValue{0}; + + auto firstJob = [&](int sleep) -> void { + std::this_thread::sleep_for(std::chrono::milliseconds{sleep}); + s().requestExclusiveAccess([&]() { + commonValue = 10; + std::this_thread::sleep_for(std::chrono::milliseconds{sleep + 10}); + UASSERT(commonValue == 10, "unexpected commonValue = " << commonValue); + }); + }; + auto secondJob = [&](int sleep) -> void { + VerilatedLockGuard lock{commonMutex}; + lock.unlock(); + s().waitIfStopRequested(); + lock.lock(); + std::this_thread::sleep_for(std::chrono::milliseconds{sleep}); + commonValue = 1000; + }; + auto thirdJob = [&](int sleep) -> void { + VerilatedLockGuard lock{commonMutex}; + std::this_thread::sleep_for(std::chrono::milliseconds{sleep}); + lock.unlock(); + s().requestExclusiveAccess([&]() { firstJob(sleep); }); + lock.lock(); + commonValue = 1000; + }; + std::list> futures; + + futures.push_back(s().enqueue(std::bind(firstJob, 100))); + futures.push_back(s().enqueue(std::bind(secondJob, 100))); + futures.push_back(s().enqueue(std::bind(firstJob, 100))); + futures.push_back(s().enqueue(std::bind(secondJob, 100))); + futures.push_back(s().enqueue(std::bind(secondJob, 200))); + futures.push_back(s().enqueue(std::bind(firstJob, 200))); + futures.push_back(s().enqueue(std::bind(firstJob, 300))); + while (!futures.empty()) { + s().waitForFuture(futures.front()); + futures.pop_front(); + } + futures.push_back(s().enqueue(std::bind(thirdJob, 100))); + futures.push_back(s().enqueue(std::bind(thirdJob, 100))); + while (!futures.empty()) { + s().waitForFuture(futures.front()); + futures.pop_front(); + } + s().waitIfStopRequested(); + s().requestExclusiveAccess(std::bind(firstJob, 100)); + auto forthJob = [&]() -> int { return 1234; }; + std::list> futuresInt; + futuresInt.push_back(s().enqueue(forthJob)); + while (!futuresInt.empty()) { + int result = s().waitForFuture(futuresInt.front()); + UASSERT(result == 1234, "unexpected future result = " << commonValue); + futuresInt.pop_front(); + } +} diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h new file mode 100644 index 000000000..b074491be --- /dev/null +++ b/src/V3ThreadPool.h @@ -0,0 +1,169 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Thread pool for Verilator itself +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2005-2023 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#ifndef _V3THREADPOOL_H_ +#define _V3THREADPOOL_H_ 1 + +#include "verilated_threads.h" + +#include +#include +#include +#include +#include +#include +#include + +//============================================================================ + +class V3ThreadPool final { + // MEMBERS + static constexpr unsigned int FUTUREWAITFOR_MS = 100; + using job_t = std::function; + + mutable VerilatedMutex m_mutex; // Mutex for use by m_queue + std::queue m_queue VL_GUARDED_BY(m_mutex); // Queue of jobs + // We don't need to guard this condition_variable as + // both `notify_one` and `notify_all` functions are atomic, + // `wait` function is not atomic, but we are guarding `m_queue` that is + // used by this condition_variable, so clang checks that we have mutex locked + std::condition_variable_any m_cv; // Conditions to wake up workers + std::list m_workers; // Worker threads + VerilatedMutex m_stoppedJobsMutex; // Used to signal stopped jobs + // Conditions to wake up stopped jobs + std::condition_variable_any m_stoppedJobsCV VL_GUARDED_BY(m_stoppedJobsMutex); + std::atomic_uint m_stoppedJobs{0}; // Currently stopped jobs waiting for wake up + std::atomic_bool m_stopRequested{false}; // Signals to resume stopped jobs + std::atomic_bool m_exclusiveAccess{false}; // Signals that all other threads are stopped + + std::atomic_bool m_shutdown{false}; // Termination pending + + // CONSTRUCTORS + V3ThreadPool() = default; + ~V3ThreadPool() { + VerilatedLockGuard lock{m_mutex}; + m_queue = {}; // make sure queue is empty + lock.unlock(); + resize(0); + } + +public: + // METHODS + // Singleton + static V3ThreadPool& s() VL_MT_SAFE { + static V3ThreadPool s_s; + return s_s; + } + + // Resize thread pool to n workers (queue must be empty) + void resize(unsigned n) VL_MT_UNSAFE; + + // Enqueue a job for asynchronous execution + template + std::future enqueue(std::function&& f) VL_MT_SAFE; + + // Request exclusive access to processing. + // It sends request to stop all other threads and waits for them to stop. + // Other threads needs to manually call 'check_stop_requested' in places where + // they can be stopped. + // When all other threads are stopped, this function executes the job + // and resumes execution of other jobs. + void requestExclusiveAccess(const job_t&& exclusiveAccessJob) VL_MT_SAFE; + + // Check if other thread requested exclusive access to processing, + // if so, it waits for it to complete. Afterwards it is resumed. + // Returns true if request was send and we waited, otherwise false + bool waitIfStopRequested() VL_MT_SAFE; + + template + T waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mutex); + + static void selfTest(); + +private: + bool willExecuteSynchronously() const VL_MT_SAFE { + return m_workers.empty() || m_exclusiveAccess; + } + + // True when any thread requested exclusive access + bool stopRequested() const VL_REQUIRES(m_stoppedJobsMutex) { + // don't wait if shutdown already requested + if (m_shutdown) return false; + return m_stopRequested; + } + + bool stopRequestedStandalone() VL_MT_SAFE_EXCLUDES(m_stoppedJobsMutex) { + const VerilatedLockGuard lock{m_stoppedJobsMutex}; + return stopRequested(); + } + + // Waits until exclusive access job completes its job + void waitStopRequested(VerilatedLockGuard& stoppedJobLock) VL_REQUIRES(m_stoppedJobsMutex); + + // Waits until all other jobs are stopped + void waitOtherThreads(VerilatedLockGuard& stoppedJobLock) VL_MT_SAFE_EXCLUDES(m_mutex) + VL_REQUIRES(m_stoppedJobsMutex); + + template + void pushJob(std::shared_ptr>& prom, std::function&& f) VL_MT_SAFE; + + void workerJobLoop(int id) VL_MT_SAFE; + + static void startWorker(V3ThreadPool* selfThreadp, int id) VL_MT_SAFE; +}; + +template +T V3ThreadPool::waitForFuture(std::future& future) VL_MT_SAFE_EXCLUDES(m_mutex) { + while (true) { + waitIfStopRequested(); + { + std::future_status status + = future.wait_for(std::chrono::milliseconds(V3ThreadPool::FUTUREWAITFOR_MS)); + switch (status) { + case std::future_status::deferred: continue; + case std::future_status::timeout: continue; + case std::future_status::ready: return future.get(); + } + } + } +} + +template +std::future V3ThreadPool::enqueue(std::function&& f) VL_MT_SAFE { + std::shared_ptr> prom = std::make_shared>(); + std::future result = prom->get_future(); + pushJob(prom, std::move(f)); + const VerilatedLockGuard guard{m_mutex}; + m_cv.notify_one(); + return result; +} + +template +void V3ThreadPool::pushJob(std::shared_ptr>& prom, + std::function&& f) VL_MT_SAFE { + if (willExecuteSynchronously()) { + prom->set_value(f()); + } else { + const VerilatedLockGuard guard{m_mutex}; + m_queue.push([prom, f] { prom->set_value(f()); }); + } +} + +template <> +void V3ThreadPool::pushJob(std::shared_ptr>& prom, + std::function&& f) VL_MT_SAFE; + +#endif // Guard diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 5b3ae150d..0a096661e 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -515,7 +515,9 @@ private: flp, new AstMulD{flp, valuep, new AstConst{flp, AstConst::RealDouble{}, m_timescaleFactor}}}; + valuep->dtypeSetBitSized(64, VSigning::UNSIGNED); } else { + valuep->dtypeSetBitSized(64, VSigning::UNSIGNED); valuep = new AstMul{flp, valuep, new AstConst{flp, AstConst::Unsized64{}, static_cast(m_timescaleFactor)}}; @@ -541,6 +543,7 @@ private: void visit(AstEventControl* nodep) override { // Do not allow waiting on local named events, as they get enqueued for clearing, but can // go out of scope before that happens + if (!nodep->sensesp()) nodep->v3warn(E_UNSUPPORTED, "Unsupported: no sense equation (@*)"); if (nodep->sensesp()->exists([](const AstNodeVarRef* refp) { AstBasicDType* const dtypep = refp->dtypep()->skipRefp()->basicp(); return dtypep && dtypep->isEvent() && refp->varp()->isFuncLocal(); diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 5a70dd3d6..398abf29a 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -46,8 +46,15 @@ class UndrivenVarEntry final { AstVar* const m_varp; // Variable this tracks std::vector m_wholeFlags; // Used/Driven on whole vector std::vector m_bitFlags; // Used/Driven on each subbit + const AstAlways* m_alwCombp + = nullptr; // always_comb of var if driven within always_comb, else nullptr + const FileLine* m_alwCombFileLinep = nullptr; // File line of always_comb of var if driven + // within always_comb, else nullptr + const AstNodeVarRef* m_nodep = nullptr; // varref if driven, else nullptr + const FileLine* m_nodeFileLinep = nullptr; // File line of varref if driven, else nullptr + bool m_underGen = false; // Under a generate - enum : uint8_t { FLAG_USED = 0, FLAG_DRIVEN = 1, FLAGS_PER_BIT = 2 }; + enum : uint8_t { FLAG_USED = 0, FLAG_DRIVEN = 1, FLAG_DRIVEN_ALWCOMB = 2, FLAGS_PER_BIT = 3 }; public: // CONSTRUCTORS @@ -117,6 +124,24 @@ public: UINFO(9, "set d[*] " << m_varp->name() << endl); m_wholeFlags[FLAG_DRIVEN] = true; } + void drivenWhole(const AstNodeVarRef* nodep, const FileLine* fileLinep) { + drivenWhole(); + m_nodep = nodep; + m_nodeFileLinep = fileLinep; + } + void drivenAlwaysCombWhole(const AstAlways* alwCombp, const FileLine* fileLinep) { + m_wholeFlags[FLAG_DRIVEN_ALWCOMB] = true; + m_alwCombp = alwCombp; + m_alwCombFileLinep = fileLinep; + } + void underGenerate() { m_underGen = true; } + bool isUnderGen() const { return m_underGen; } + bool isDrivenWhole() const { return m_wholeFlags[FLAG_DRIVEN]; } + bool isDrivenAlwaysCombWhole() const { return m_wholeFlags[FLAG_DRIVEN_ALWCOMB]; } + const AstNodeVarRef* getNodep() const { return m_nodep; } + const FileLine* getNodeFileLinep() const { return m_nodeFileLinep; } + const AstAlways* getAlwCombp() const { return m_alwCombp; } + const FileLine* getAlwCombFileLinep() const { return m_alwCombFileLinep; } void usedBit(int bit, int width) { UINFO(9, "set u[" << (bit + width - 1) << ":" << bit << "] " << m_varp->name() << endl); for (int i = 0; i < width; i++) { @@ -304,7 +329,7 @@ private: for (int usr = 1; usr < (m_alwaysCombp ? 3 : 2); ++usr) { // For assigns and non-combo always, do just usr==1, to look // for module-wide undriven etc. - // For non-combo always, run both usr==1 for above, and also + // For combo always, run both usr==1 for above, and also // usr==2 for always-only checks. UndrivenVarEntry* const entryp = getEntryp(nodep, usr); if (nodep->isNonOutput() || nodep->isSigPublic() || nodep->isSigUserRWPublic() @@ -381,7 +406,44 @@ private: UINFO(9, " Full bus. Entryp=" << cvtToHex(entryp) << endl); warnAlwCombOrder(nodep); } - entryp->drivenWhole(); + if (entryp->isDrivenWhole() && !m_inBBox && !VN_IS(nodep, VarXRef) + && !VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType) + && nodep->fileline() != entryp->getNodeFileLinep() && !entryp->isUnderGen() + && entryp->getNodep()) { + if (m_alwaysCombp + && (!entryp->isDrivenAlwaysCombWhole() + || (entryp->isDrivenAlwaysCombWhole() + && m_alwaysCombp != entryp->getAlwCombp() + && m_alwaysCombp->fileline() != entryp->getAlwCombFileLinep()))) { + nodep->v3warn( + MULTIDRIVEN, + "Variable written to in always_comb also written by other process" + << " (IEEE 1800-2017 9.2.2.2): " << nodep->prettyNameQ() << '\n' + << nodep->warnOther() << '\n' + << nodep->warnContextPrimary() << '\n' + << entryp->getNodep()->warnOther() + << "... Location of other write\n" + << entryp->getNodep()->warnContextSecondary()); + } + if (!m_alwaysCombp && entryp->isDrivenAlwaysCombWhole()) { + nodep->v3warn(MULTIDRIVEN, + "Variable also written to in always_comb" + << " (IEEE 1800-2017 9.2.2.2): " << nodep->prettyNameQ() + << '\n' + << nodep->warnOther() << '\n' + << nodep->warnContextPrimary() << '\n' + << entryp->getNodep()->warnOther() + << "... Location of always_comb write\n" + << entryp->getNodep()->warnContextSecondary()); + } + } + entryp->drivenWhole(nodep, nodep->fileline()); + if (m_alwaysCombp && entryp->isDrivenAlwaysCombWhole() + && m_alwaysCombp != entryp->getAlwCombp() + && m_alwaysCombp->fileline() == entryp->getAlwCombFileLinep()) + entryp->underGenerate(); + if (m_alwaysCombp) + entryp->drivenAlwaysCombWhole(m_alwaysCombp, m_alwaysCombp->fileline()); } if (m_inBBox || nodep->access().isReadOrRW() || fdrv diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 258c98506..2f0eabfb0 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -439,7 +439,7 @@ private: } else if (VN_IS(basefromp, Const)) { // If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp } else { - nodep->v3fatalSrc("No VarRef or Const under ArraySel"); + // Normally one of above, but might have MEMBERSEL or otherwise } // Find range of dtype we are selecting from int declElements = -1; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 32899dce3..89ee71e5a 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -106,6 +106,7 @@ std::ostream& operator<<(std::ostream& str, const Determ& rhs) { enum Castable : uint8_t { UNSUPPORTED, + SAMEISH, COMPATIBLE, ENUM_EXPLICIT, ENUM_IMPLICIT, @@ -114,10 +115,18 @@ enum Castable : uint8_t { }; std::ostream& operator<<(std::ostream& str, const Castable& rhs) { static const char* const s_det[] - = {"UNSUP", "COMPAT", "ENUM_EXP", "ENUM_IMP", "DYN_CLS", "INCOMPAT"}; + = {"UNSUP", "IDENT", "COMPAT", "ENUM_EXP", "ENUM_IMP", "DYN_CLS", "INCOMPAT"}; return str << s_det[rhs]; } +#define v3widthWarn(lhs, rhs, msg) \ + v3errorEnd((V3Error::s().m_mutex.lock(), \ + V3Error::s().v3errorPrep((lhs) < (rhs) ? V3ErrorCode::WIDTHTRUNC \ + : (lhs) > (rhs) ? V3ErrorCode::WIDTHEXPAND \ + : V3ErrorCode::WIDTH), \ + (V3Error::s().v3errorStr() << msg), V3Error::s().v3errorStr())), \ + V3Error::s().m_mutex.unlock() + //###################################################################### // Width state, as a visitor of each AstNode @@ -306,6 +315,9 @@ private: void visit(AstLteN* nodep) override { visit_cmp_string(nodep); } void visit(AstGtN* nodep) override { visit_cmp_string(nodep); } void visit(AstGteN* nodep) override { visit_cmp_string(nodep); } + // ... Data type compares + void visit(AstEqT* nodep) override { visit_cmp_type(nodep); } + void visit(AstNeqT* nodep) override { visit_cmp_type(nodep); } // Widths: out width = lhs width = rhs width // Signed: Output signed iff LHS & RHS signed. @@ -451,6 +463,13 @@ private: } } } + void visit(AstNToI* nodep) override { + // Created here, should be already sized + if (m_vup->prelim()) { + UASSERT_OBJ(nodep->dtypep(), nodep, "NToI should be sized when created"); + iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); + } + } // Widths: Constant, terminal void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); } @@ -501,7 +520,7 @@ private: if (m_vup->final()) { AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); AstNodeDType* const subDTypep = expDTypep; - nodep->dtypeFrom(expDTypep); + nodep->dtypep(expDTypep); // Error report and change sizes for suboperands of this node. iterateCheck(nodep, "Conditional True", nodep->thenp(), CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP); @@ -714,12 +733,24 @@ private: << vdtypep->prettyDTypeNameQ() << " data type"); } - // Don't iterate lhsp as SELF, the potential Concat below needs - // the adtypep passed down to recognize the QueueDType - userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, BOTH}.p()); - nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - return; + if (VN_IS(nodep->lhsp(), Concat)) { + // Convert to concat directly, and visit(AstConst) will convert. + // Don't iterate lhsp as SELF, the potential Concat below needs + // the adtypep passed down to recognize the QueueDType + userIterateAndNext(nodep->lhsp(), WidthVP{vdtypep, BOTH}.p()); + nodep->replaceWith(nodep->lhsp()->unlinkFrBack()); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } else { // int a[] = {lhs} -> same as '{lhs} + auto* const newp = new AstPattern{ + nodep->fileline(), + new AstPatMember{nodep->lhsp()->fileline(), nodep->lhsp()->unlinkFrBack(), + nullptr, nullptr}}; + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + userIterate(newp, m_vup); + return; + } } if (VN_IS(vdtypep, AssocArrayDType)) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Replication to form " @@ -829,7 +860,7 @@ private: // Note width() not set on range; use elementsConst() if (nodep->littleEndian() && !VN_IS(nodep->backp(), UnpackArrayDType) && !VN_IS(nodep->backp(), Cell)) { // For cells we warn in V3Inst - nodep->v3warn(LITENDIAN, "Little bit endian vector: left < right of bit range: [" + nodep->v3warn(LITENDIAN, "Big bit endian vector: left < right of bit range: [" << nodep->leftConst() << ":" << nodep->rightConst() << "]"); } @@ -898,15 +929,16 @@ private: userIterateAndNext(nodep->lsbp(), WidthVP{SELF, FINAL}.p()); if (widthBad(nodep->lsbp(), selwidthDTypep) && nodep->lsbp()->width() != 32) { if (!nodep->fileline()->warnIsOff(V3ErrorCode::WIDTH)) { - nodep->v3warn(WIDTH, - "Bit extraction of var[" - << (frommsb / elw) << ":" << (fromlsb / elw) << "] requires " - << (selwidth / elw) << " bit index, not " - << (nodep->lsbp()->width() / elw) - << (nodep->lsbp()->width() != nodep->lsbp()->widthMin() - ? " or " + cvtToStr(nodep->lsbp()->widthMin() / elw) - : "") - << " bits."); + nodep->v3widthWarn( + (selwidth / elw), (nodep->lsbp()->width() / elw), + "Bit extraction of var[" + << (frommsb / elw) << ":" << (fromlsb / elw) << "] requires " + << (selwidth / elw) << " bit index, not " + << (nodep->lsbp()->width() / elw) + << (nodep->lsbp()->width() != nodep->lsbp()->widthMin() + ? " or " + cvtToStr(nodep->lsbp()->widthMin() / elw) + : "") + << " bits."); UINFO(1, " Related node: " << nodep << endl); } } @@ -976,13 +1008,14 @@ private: AstNodeDType* const selwidthDTypep = nodep->findLogicDType(selwidth, selwidth, nodep->bitp()->dtypep()->numeric()); if (widthBad(nodep->bitp(), selwidthDTypep) && nodep->bitp()->width() != 32) { - nodep->v3warn(WIDTH, "Bit extraction of array[" - << frommsb << ":" << fromlsb << "] requires " << selwidth - << " bit index, not " << nodep->bitp()->width() - << (nodep->bitp()->width() != nodep->bitp()->widthMin() - ? " or " + cvtToStr(nodep->bitp()->widthMin()) - : "") - << " bits."); + nodep->v3widthWarn(selwidth, nodep->bitp()->width(), + "Bit extraction of array[" + << frommsb << ":" << fromlsb << "] requires " << selwidth + << " bit index, not " << nodep->bitp()->width() + << (nodep->bitp()->width() != nodep->bitp()->widthMin() + ? " or " + cvtToStr(nodep->bitp()->widthMin()) + : "") + << " bits."); if (!nodep->fileline()->warnIsOff(V3ErrorCode::WIDTH)) { UINFO(1, " Related node: " << nodep << endl); UINFO(1, " Related dtype: " << nodep->dtypep() << endl); @@ -1177,6 +1210,7 @@ private: void visit(AstFell* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); + userIterate(nodep->sentreep(), nullptr); nodep->dtypeSetBit(); } } @@ -1207,6 +1241,7 @@ private: void visit(AstRose* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); + userIterate(nodep->sentreep(), nullptr); nodep->dtypeSetBit(); } } @@ -1221,6 +1256,7 @@ private: void visit(AstStable* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); + userIterate(nodep->sentreep(), nullptr); nodep->dtypeSetBit(); } } @@ -1286,7 +1322,7 @@ private: } if (m_vup->final()) { AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); - nodep->dtypeFrom(expDTypep); // Assume user knows the rules; go with the flow + nodep->dtypep(expDTypep); // Assume user knows the rules; go with the flow if (nodep->width() > 64) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: $c can't generate wider than 64 bits"); } @@ -1317,7 +1353,7 @@ private: if (m_vup->final()) { AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); - nodep->dtypeFrom(expDTypep); + nodep->dtypep(expDTypep); // rhs already finalized in iterate_shift_prelim iterateCheck(nodep, "LHS", nodep->lhsp(), SELF, FINAL, nodep->dtypep(), EXTEND_EXP); AstNode* newp = nullptr; // No change @@ -1429,8 +1465,6 @@ private: // Don't iterate children, don't want to lose VarRef. switch (nodep->attrType()) { case VAttrType::VAR_BASE: - case VAttrType::MEMBER_BASE: - case VAttrType::ENUM_BASE: // Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf break; case VAttrType::DIM_DIMENSIONS: @@ -1546,6 +1580,10 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); break; } + case VAttrType::TYPEID: + // Soon to be handled in AstEqT + nodep->dtypeSetSigned32(); + break; default: { // Everything else resolved earlier nodep->dtypeSetLogicUnsized(32, 1, VSigning::UNSIGNED); // Approximation, unsized 32 @@ -1712,12 +1750,19 @@ private: if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed nodep->doingWidth(true); if (nodep->typeofp()) { // type(typeofp_expression) - // Type comes from expression's type - userIterateAndNext(nodep->typeofp(), WidthVP{SELF, BOTH}.p()); - AstNode* const typeofp = nodep->typeofp(); - nodep->typedefp(nullptr); - nodep->refDTypep(typeofp->dtypep()); - VL_DO_DANGLING(typeofp->unlinkFrBack()->deleteTree(), typeofp); + if (AstNodeDType* typeofDtp = VN_CAST(nodep->typeofp(), NodeDType)) { + // It's directly a type, e.g. "type(int)" + typeofDtp = iterateEditMoveDTypep(nodep, typeofDtp); // Changes typeofp + nodep->typedefp(nullptr); + nodep->refDTypep(typeofDtp); + } else { + // Type comes from expression's type, e.g. "type(variable)" + userIterateAndNext(nodep->typeofp(), WidthVP{SELF, BOTH}.p()); + AstNode* const typeofp = nodep->typeofp(); + nodep->typedefp(nullptr); + nodep->refDTypep(typeofp->dtypep()); + VL_DO_DANGLING(typeofp->unlinkFrBack()->deleteTree(), typeofp); + } // We had to use AstRefDType for this construct as pointers to this type // in type table are still correct (which they wouldn't be if we replaced the node) } @@ -1811,7 +1856,7 @@ private: nodep->fromp()->unlinkFrBack()}, new AstConst{fl, AstConst::Signed32{}, 1}}, new AstConst{fl, AstConst::Signed32{}, 0}}; - } else if (castable == COMPATIBLE) { + } else if (castable == SAMEISH || castable == COMPATIBLE) { nodep->v3warn(CASTCONST, "$cast will always return one as " << toDtp->prettyDTypeNameQ() << " is always castable from " @@ -1874,7 +1919,7 @@ private: << toDtp->prettyDTypeNameQ() << " from " << fromDtp->prettyDTypeNameQ()); bad = true; - } else if (castable == COMPATIBLE || castable == ENUM_IMPLICIT + } else if (castable == SAMEISH || castable == COMPATIBLE || castable == ENUM_IMPLICIT || castable == ENUM_EXPLICIT) { ; // Continue } else if (castable == DYNAMIC_CLASS) { @@ -1897,7 +1942,9 @@ private: AstNodeExpr* newp = nullptr; if (bad) { } else if (const AstBasicDType* const basicp = toDtp->basicp()) { - if (!basicp->isDouble() && !fromDtp->isDouble()) { + if (!basicp->isString() && fromDtp->isString()) { + newp = new AstNToI{nodep->fileline(), nodep->fromp()->unlinkFrBack(), toDtp}; + } else if (!basicp->isDouble() && !fromDtp->isDouble()) { AstNodeDType* const origDTypep = nodep->dtypep(); const int width = toDtp->width(); castSized(nodep, nodep->fromp(), width); @@ -1907,21 +1954,16 @@ private: iterateCheck(nodep, "value", nodep->fromp(), SELF, FINAL, fromDtp, EXTEND_EXP, false); } - if (basicp->isDouble() && !nodep->fromp()->isDouble()) { + if (newp) { + } else if (basicp->isDouble() && !nodep->fromp()->isDouble()) { if (nodep->fromp()->isSigned()) { newp = new AstISToRD{nodep->fileline(), nodep->fromp()->unlinkFrBack()}; } else { newp = new AstIToRD{nodep->fileline(), nodep->fromp()->unlinkFrBack()}; } } else if (!basicp->isDouble() && nodep->fromp()->isDouble()) { - if (basicp->isSigned()) { - newp - = new AstRToIRoundS{nodep->fileline(), nodep->fromp()->unlinkFrBack()}; - } else { - newp = new AstUnsigned{ - nodep->fileline(), - new AstRToIS{nodep->fileline(), nodep->fromp()->unlinkFrBack()}}; - } + newp = new AstRToIRoundS{nodep->fileline(), nodep->fromp()->unlinkFrBack()}; + newp->dtypeChgSigned(basicp->isSigned()); } else if (basicp->isSigned() && !nodep->fromp()->isSigned()) { newp = new AstSigned{nodep->fileline(), nodep->fromp()->unlinkFrBack()}; } else if (!basicp->isSigned() && nodep->fromp()->isSigned()) { @@ -2128,6 +2170,7 @@ private: userIterateAndNext(nodep->valuep(), WidthVP{nodep->dtypep(), PRELIM}.p()); iterateCheckAssign(nodep, "Initial value", nodep->valuep(), FINAL, nodep->dtypep()); } + userIterateAndNext(nodep->delayp(), WidthVP{nodep->dtypep(), PRELIM}.p()); UINFO(4, "varWidthed " << nodep << endl); // if (debug()) nodep->dumpTree("- InitOut: "); nodep->didWidth(true); @@ -2245,10 +2288,17 @@ private: if (nodep->valuep()) { // else the value will be assigned sequentially // Default type is int, but common to assign narrower values, so minwidth from value userIterateAndNext(nodep->valuep(), WidthVP{CONTEXT_DET, PRELIM}.p()); + bool warnOn = true; + if (const AstConst* const constp = VN_CAST(nodep->valuep(), Const)) { + if (static_cast(constp->num().mostSetBitP1()) > nodep->width()) { + constp->v3error("Enum value exceeds width of enum type (IEEE 1800-2017 6.19)"); + warnOn = false; // Prevent normal WIDTHTRUNC + } + } // Minwidth does not come from value, as spec says set based on parent // and if we keep minwidth we'll consider it unsized which is incorrect iterateCheck(nodep, "Enum value", nodep->valuep(), CONTEXT_DET, FINAL, nodep->dtypep(), - EXTEND_EXP); + EXTEND_EXP, warnOn); // Always create a cast, to avoid later ENUMVALUE warnings nodep->valuep(new AstCast{nodep->valuep()->fileline(), nodep->valuep()->unlinkFrBack(), nodep->dtypep()}); @@ -2317,6 +2367,18 @@ private: EXTEND_EXP); } } + void visit(AstConsPackUOrStruct* nodep) override { + // Type was computed when constructed in V3Width earlier + auto* const vdtypep = VN_AS(nodep->dtypep()->skipRefp(), NodeUOrStructDType); + UASSERT_OBJ(vdtypep, nodep, "ConsPackUOrStruct requires packed array parent data type"); + userIterateChildren(nodep, WidthVP{vdtypep, BOTH}.p()); + } + void visit(AstConsPackMember* nodep) override { + // Type was computed when constructed in V3Width earlier + auto* const vdtypep = VN_AS(nodep->dtypep(), MemberDType); + UASSERT_OBJ(vdtypep, nodep, "ConsPackMember requires member data type"); + if (m_vup->prelim()) userIterateAndNext(nodep->rhsp(), WidthVP{vdtypep, BOTH}.p()); + } void visit(AstConsDynArray* nodep) override { // Type computed when constructed here AstDynArrayDType* const vdtypep = VN_AS(m_vup->dtypep()->skipRefp(), DynArrayDType); @@ -2476,33 +2538,45 @@ private: } void visit(AstNodeUOrStructDType* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed - UINFO(5, " NODECLASS " << nodep << endl); + UINFO(5, " NODEUORS " << nodep << endl); // if (debug() >= 9) nodep->dumpTree("- class-in: "); - if (!nodep->packed()) { - if (VN_IS(nodep, UnionDType)) { - nodep->v3warn(UNPACKED, "Unsupported: Unpacked union"); - } else if (v3Global.opt.structsPacked()) { - nodep->packed(true); - } - } + if (!nodep->packed() && v3Global.opt.structsPacked()) nodep->packed(true); userIterateChildren(nodep, nullptr); // First size all members nodep->repairMemberCache(); nodep->dtypep(nodep); nodep->isFourstate(false); + // Error checks + for (AstMemberDType* itemp = nodep->membersp(); itemp; + itemp = VN_AS(itemp->nextp(), MemberDType)) { + AstNodeDType* const dtp = itemp->subDTypep()->skipRefp(); + if (nodep->packed() + && !dtp->isIntegralOrPacked() + // Historically lax: + && !v3Global.opt.structsPacked()) + itemp->v3error("Unpacked data type " + << dtp->prettyDTypeNameQ() + << " in packed struct/union (IEEE 1800-2017 7.2.1)"); + if ((VN_IS(nodep, UnionDType) || nodep->packed()) && itemp->valuep()) { + itemp->v3error("Initial values not allowed in packed struct/union" + " (IEEE 1800-2017 7.2.1)"); + pushDeletep(itemp->valuep()->unlinkFrBack()); + } else if (itemp->valuep()) { + itemp->valuep()->v3warn(E_UNSUPPORTED, + "Unsupported: Initial values in struct/union members"); + pushDeletep(itemp->valuep()->unlinkFrBack()); + } + } // Determine bit assignments and width if (VN_IS(nodep, UnionDType) || nodep->packed()) { int lsb = 0; int width = 0; - // MSB is first, so go backwards + // Report errors on first member first AstMemberDType* itemp; + // MSB is first, so loop backwards for (itemp = nodep->membersp(); itemp && itemp->nextp(); itemp = VN_AS(itemp->nextp(), MemberDType)) {} - for (AstMemberDType* backip; itemp; itemp = backip) { - if (itemp->skipRefp()->isCompound()) - itemp->v3error( - "Unpacked data type in packed struct/union (IEEE 1800-2017 7.2.1)"); + for (; itemp; itemp = VN_CAST(itemp->backp(), MemberDType)) { if (itemp->isFourstate()) nodep->isFourstate(true); - backip = VN_CAST(itemp->backp(), MemberDType); itemp->lsb(lsb); if (VN_IS(nodep, UnionDType)) { width = std::max(width, itemp->width()); @@ -2563,6 +2637,10 @@ private: nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep())); nodep->dtypep(nodep); // The member itself, not subDtype nodep->widthFromSub(nodep->subDTypep()); + if (nodep->valuep()) { + userIterateAndNext(nodep->valuep(), WidthVP{nodep->dtypep(), PRELIM}.p()); + iterateCheckAssign(nodep, "Initial value", nodep->valuep(), FINAL, nodep->dtypep()); + } } void visit(AstStructSel* nodep) override { userIterateChildren(nodep, WidthVP{SELF, BOTH}.p()); @@ -2853,34 +2931,47 @@ private: VAttrType attrType; if (nodep->name() == "name") { attrType = VAttrType::ENUM_NAME; + methodOkArguments(nodep, 0, 0); } else if (nodep->name() == "next") { attrType = VAttrType::ENUM_NEXT; + methodOkArguments(nodep, 0, 1); } else if (nodep->name() == "prev") { attrType = VAttrType::ENUM_PREV; + methodOkArguments(nodep, 0, 1); } else { nodep->v3fatalSrc("Bad case"); } - if (nodep->name() == "name") { - methodOkArguments(nodep, 0, 0); - } else if (nodep->pinsp() && !(VN_IS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const))) { - nodep->pinsp()->v3fatalSrc("Unsupported: enum next/prev with non-const argument"); - } else if (nodep->pinsp() - && !(VN_IS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const) - && VN_AS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)->toUInt() == 1 - && !nodep->pinsp()->nextp())) { - // Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1) - AstMethodCall* const clonep = nodep->cloneTree(false); - VN_AS(VN_AS(clonep->pinsp(), Arg)->exprp(), Const)->num().setLong(1); - const uint32_t stepWidth - = VN_AS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)->toUInt(); - AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1); - AstArg* const argp = new AstArg{nodep->fileline(), "", constp}; - AstMethodCall* const newp - = new AstMethodCall{nodep->fileline(), clonep, nodep->name(), argp}; - nodep->replaceWith(newp); - VL_DO_DANGLING(nodep->deleteTree(), nodep); - return; + if (nodep->name() != "name" && nodep->pinsp()) { + if (!VN_IS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)) { + nodep->pinsp()->v3fatalSrc( + "Unsupported: enum next/prev with non-const argument"); + } else { + const uint32_t stepWidth + = VN_AS(VN_AS(nodep->pinsp(), Arg)->exprp(), Const)->toUInt(); + if (stepWidth == 0) { + // Step of 0 "legalizes" like $cast, use .next.prev + AstMethodCall* const newp = new AstMethodCall{ + nodep->fileline(), + new AstMethodCall{nodep->fileline(), nodep->fromp()->unlinkFrBack(), + "next", nullptr}, + "prev", nullptr}; + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return; + } else if (stepWidth != 1) { + // Unroll of enumVar.next(k) to enumVar.next(1).next(k - 1) + AstMethodCall* const clonep = nodep->cloneTree(false); + VN_AS(VN_AS(clonep->pinsp(), Arg)->exprp(), Const)->num().setLong(1); + AstConst* const constp = new AstConst(nodep->fileline(), stepWidth - 1); + AstArg* const argp = new AstArg{nodep->fileline(), "", constp}; + AstMethodCall* const newp + = new AstMethodCall{nodep->fileline(), clonep, nodep->name(), argp}; + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return; + } + } } // Need a runtime lookup table. Yuk. const uint64_t msbdim = enumMaxValue(nodep, adtypep); @@ -3364,7 +3455,7 @@ private: UASSERT_OBJ(first_classp, nodep, "Unlinked"); for (AstClass* classp = first_classp; classp;) { if (nodep->fileline()->timingOn()) { - if (classp->name() == "semaphore" + if (classp->name() == "semaphore" || classp->name() == "process" || VString::startsWith(classp->name(), "mailbox")) { // Find the package the class is in AstNode* pkgItemp = classp; @@ -3627,7 +3718,7 @@ private: // Either made explicitly or V3LinkDot made implicitly classp->v3fatalSrc("Can't find class's new"); } - if (classp->isVirtual()) { + if (classp->isVirtual() || classp->isInterfaceClass()) { nodep->v3error( "Illegal to call 'new' using an abstract virtual class (IEEE 1800-2017 8.21)"); } @@ -3838,26 +3929,45 @@ private: } } AstNodeExpr* newp = nullptr; - for (AstMemberDType* memp = vdtypep->membersp(); memp; - memp = VN_AS(memp->nextp(), MemberDType)) { - const auto it = patmap.find(memp); - AstPatMember* patp = nullptr; - if (it == patmap.end()) { - // default or default_type assignment - if (AstNodeUOrStructDType* const memp_nested_vdtypep - = VN_CAST(memp->virtRefDTypep(), NodeUOrStructDType)) { - newp = nestedvalueConcat_patternUOrStruct(memp_nested_vdtypep, defaultp, newp, - nodep, dtypemap); - } else { - patp = Defaultpatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp, - dtypemap); + if (vdtypep->packed()) { + for (AstMemberDType* memp = vdtypep->membersp(); memp; + memp = VN_AS(memp->nextp(), MemberDType)) { + const auto it = patmap.find(memp); + AstPatMember* patp = nullptr; + if (it == patmap.end()) { // default or default_type assignment + if (AstNodeUOrStructDType* const memp_nested_vdtypep + = VN_CAST(memp->virtRefDTypep(), NodeUOrStructDType)) { + newp = nestedvalueConcat_patternUOrStruct(memp_nested_vdtypep, defaultp, + newp, nodep, dtypemap); + } else { + patp = defaultPatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp, + dtypemap); + newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep); + } + } else { // member assignment + patp = it->second; newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep); } - } else { - // member assignment - patp = it->second; - newp = valueConcat_patternUOrStruct(patp, newp, memp, nodep); } + } else { // Unpacked + AstConsPackMember* membersp = nullptr; + for (AstMemberDType* memp = vdtypep->membersp(); memp; + memp = VN_AS(memp->nextp(), MemberDType)) { + const auto it = patmap.find(memp); + AstPatMember* patp = nullptr; + if (it == patmap.end()) { // Default or default_type assignment + patp = defaultPatp_patternUOrStruct(nodep, memp, patp, vdtypep, defaultp, + dtypemap); + } else { + patp = it->second; // Member assignment + } + patp->dtypep(memp); + AstNodeExpr* const valuep = patternMemberValueIterate(patp); + AstConsPackMember* const cpmp + = new AstConsPackMember{patp->fileline(), memp, valuep}; + membersp = membersp ? membersp->addNext(cpmp) : cpmp; + } + newp = new AstConsPackUOrStruct{nodep->fileline(), vdtypep, membersp}; } if (newp) { nodep->replaceWith(newp); @@ -3880,7 +3990,7 @@ private: newp = nestedvalueConcat_patternUOrStruct(memp_multinested_vdtypep, defaultp, newp, nodep, dtypemap); } else { - patp = Defaultpatp_patternUOrStruct(nodep, memp_nested, patp, memp_vdtypep, + patp = defaultPatp_patternUOrStruct(nodep, memp_nested, patp, memp_vdtypep, defaultp, dtypemap); newp = valueConcat_patternUOrStruct(patp, newp, memp_nested, nodep); } @@ -3888,7 +3998,7 @@ private: return newp; } - AstPatMember* Defaultpatp_patternUOrStruct(AstPattern* nodep, AstMemberDType* memp, + AstPatMember* defaultPatp_patternUOrStruct(AstPattern* nodep, AstMemberDType* memp, AstPatMember* patp, AstNodeUOrStructDType* memp_vdtypep, AstPatMember* defaultp, const DTypeMap& dtypemap) { @@ -4183,6 +4293,45 @@ private: } } + // Deal with case(type(data_type)) + if (AstAttrOf* const exprap = VN_CAST(nodep->exprp(), AttrOf)) { + if (exprap->attrType() == VAttrType::TYPEID) { + AstNodeDType* const exprDtp = VN_AS(exprap->fromp(), NodeDType); + UINFO(9, "case type exprDtp " << exprDtp << endl); + // V3Param may have a pointer to this case statement, and we need + // dotted references to remain properly named, so rather than + // removing we convert it to a "normal" expression "case (1) ..." + FileLine* const newfl = nodep->fileline(); + newfl->warnOff(V3ErrorCode::CASEINCOMPLETE, true); // Side effect of transform + newfl->warnOff(V3ErrorCode::CASEOVERLAP, true); // Side effect of transform + nodep->fileline(newfl); + for (AstCaseItem* itemp = nodep->itemsp(); itemp; + itemp = VN_AS(itemp->nextp(), CaseItem)) { + if (!itemp->isDefault()) { + bool hit = false; + for (AstNode* condp = itemp->condsp(); condp; condp = condp->nextp()) { + const AstAttrOf* const condAttrp = VN_CAST(condp, AttrOf); + if (!condAttrp) { + condp->v3error( + "Case(type) statement requires items that have type() items"); + } else { + AstNodeDType* const condDtp = VN_AS(condAttrp->fromp(), NodeDType); + if (computeCastable(exprDtp, condDtp, nodep) == SAMEISH) { + hit = true; + break; + } + } + } + pushDeletep(itemp->condsp()->unlinkFrBackWithNext()); + // Item condition becomes constant 1 if hits else 0 + itemp->addCondsp(new AstConst{newfl, AstConst::BitTrue{}, hit}); + } + } + VL_DO_DANGLING(pushDeletep(exprap->unlinkFrBack()), exprap); + nodep->exprp(new AstConst{newfl, AstConst::BitTrue{}}); + } + } + // Take width as maximum across all items, if any is real whole thing is real AstNodeDType* subDTypep = nodep->exprp()->dtypep(); for (AstCaseItem* itemp = nodep->itemsp(); itemp; @@ -4557,12 +4706,12 @@ private: if (!inPct && ch == '%') { inPct = true; fmt = ch; - } else if (inPct && (isdigit(ch) || ch == '.' || ch == '-')) { + } else if (inPct && (std::isdigit(ch) || ch == '.' || ch == '-')) { fmt += ch; } else if (inPct) { inPct = false; bool added = false; - switch (tolower(ch)) { + switch (std::tolower(ch)) { case '%': break; // %% - just output a % case 'm': break; // %m - auto insert "name" case 'l': break; // %m - auto insert "library" @@ -4594,8 +4743,8 @@ private: || VN_IS(dtypep, DynArrayDType) // || VN_IS(dtypep, UnpackArrayDType) // || VN_IS(dtypep, QueueDType) - || (VN_IS(dtypep, StructDType) - && !VN_AS(dtypep, StructDType)->packed())) { + || (VN_IS(dtypep, NodeUOrStructDType) + && !VN_AS(dtypep, NodeUOrStructDType)->packed())) { added = true; newFormat += "%@"; VNRelinker handle; @@ -4729,8 +4878,8 @@ private: void visit(AstFError* nodep) override { if (m_vup->prelim()) { iterateCheckFileDesc(nodep, nodep->filep(), BOTH); - // We only support string types, not packed array - iterateCheckString(nodep, "$ferror string result", nodep->strp(), BOTH); + // Could be string or packed array + userIterateAndNext(nodep->strp(), WidthVP{SELF, BOTH}.p()); nodep->dtypeSetLogicUnsized(32, 1, VSigning::SIGNED); // Spec says integer return } } @@ -5079,9 +5228,13 @@ private: // Grab width from the output variable (if it's a function) if (nodep->didWidth()) return; if (nodep->doingWidth()) { - UINFO(5, "Recursive function or task call: " << nodep); - nodep->v3warn(E_UNSUPPORTED, "Unsupported: Recursive function or task call: " - << nodep->prettyNameQ()); + if (nodep->classMethod()) { + UINFO(5, "Recursive method call: " << nodep); + } else { + UINFO(5, "Recursive function or task call: " << nodep); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: Recursive function or task call: " + << nodep->prettyNameQ()); + } nodep->recursive(true); nodep->didWidth(true); return; @@ -5371,9 +5524,15 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { userIterateChildren(nodep, WidthVP{SELF, BOTH}.p()); - if (nodep->edgeType().anEdge() && nodep->sensp()->dtypep()->skipRefp()->isDouble()) { - nodep->sensp()->v3error( - "Edge event control not legal on real type (IEEE 1800-2017 6.12.1)"); + if (nodep->edgeType().anEdge()) { + AstNodeDType* const sensDtp = nodep->sensp()->dtypep()->skipRefp(); + if (sensDtp->isDouble()) { + nodep->sensp()->v3error( + "Edge event control not legal on real type (IEEE 1800-2017 6.12.1)"); + } else if (sensDtp->basicp() && !sensDtp->basicp()->keyword().isIntNumeric()) { + nodep->sensp()->v3error("Edge event control not legal on non-integral type " + "(IEEE 1800-2017 9.4.2)"); + } } } } @@ -5666,6 +5825,32 @@ private: nodep->dtypeSetBit(); } } + void visit_cmp_type(AstNodeBiop* nodep) { + // CALLER: EqT, LtT + // Widths: 1 bit out + // Data type compare (not output) + if (m_vup->prelim()) { + userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p()); + userIterateAndNext(nodep->rhsp(), WidthVP{SELF, BOTH}.p()); + const AstAttrOf* const lhsap = VN_AS(nodep->lhsp(), AttrOf); + const AstAttrOf* const rhsap = VN_AS(nodep->rhsp(), AttrOf); + UASSERT_OBJ(lhsap->attrType() == VAttrType::TYPEID, lhsap, + "Type compare expects type reference"); + UASSERT_OBJ(rhsap->attrType() == VAttrType::TYPEID, rhsap, + "Type compare expects type reference"); + AstNodeDType* const lhsDtp = VN_AS(lhsap->fromp(), NodeDType); + AstNodeDType* const rhsDtp = VN_AS(rhsap->fromp(), NodeDType); + UINFO(9, "==type lhsDtp " << lhsDtp << endl); + UINFO(9, "==type rhsDtp " << lhsDtp << endl); + const bool invert = VN_IS(nodep, NeqT); + const bool identical = computeCastable(lhsDtp, rhsDtp, nodep) == SAMEISH; + UINFO(9, "== " << identical << endl); + const bool eq = invert ^ identical; + AstNode* const newp = new AstConst{nodep->fileline(), AstConst::BitTrue{}, eq}; + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } + } void visit_negate_not(AstNodeUniop* nodep, bool real_ok) { // CALLER: (real_ok=false) Not @@ -5755,7 +5940,7 @@ private: if (m_vup->final()) { AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); AstNodeDType* const subDTypep = expDTypep; - nodep->dtypeFrom(expDTypep); + nodep->dtypep(expDTypep); // ShiftRS converts to ShiftR, but not vice-versa if (VN_IS(nodep, ShiftRS)) { if (AstNodeBiop* const newp = replaceWithUOrSVersion(nodep, nodep->isSigned())) { @@ -5807,7 +5992,7 @@ private: if (m_vup->final()) { AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); AstNodeDType* const subDTypep = expDTypep; - nodep->dtypeFrom(expDTypep); + nodep->dtypep(expDTypep); // Error report and change sizes for suboperands of this node. iterateCheck(nodep, "LHS", nodep->lhsp(), CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP); iterateCheck(nodep, "RHS", nodep->rhsp(), CONTEXT_DET, FINAL, subDTypep, EXTEND_EXP); @@ -5857,7 +6042,7 @@ private: // Parent's data type was computed using the max(upper, nodep->dtype) AstNodeDType* const expDTypep = m_vup->dtypeOverridep(nodep->dtypep()); AstNodeDType* const subDTypep = expDTypep; - nodep->dtypeFrom(expDTypep); + nodep->dtypep(expDTypep); // We don't use LHS && RHS -- unspecified language corner, see t_math_signed5 test // bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned()); if (AstNodeBiop* const newp = replaceWithUOrSVersion(nodep, expDTypep->isSigned())) { @@ -5983,7 +6168,7 @@ private: AstNodeExpr* const newp = spliceCvtD(nodep); nodep = newp; } - nodep->dtypeFrom(expDTypep); + nodep->dtypep(expDTypep); UINFO(4, " _new: " << nodep << endl); } @@ -6037,8 +6222,9 @@ private: else if (!constp->num().sized() // Make it the proper size. Careful of proper extension of 0's/1's && expWidth > 32 && constp->num().isMsbXZ()) { - constp->v3warn(WIDTH, "Unsized constant being X/Z extended to " - << expWidth << " bits: " << constp->prettyName()); + constp->v3warn(WIDTHXZEXPAND, "Unsized constant being X/Z extended to " + << expWidth + << " bits: " << constp->prettyName()); V3Number num(constp, expWidth); num.opExtendXZ(constp->num(), constp->width()); AstNodeExpr* const newp = new AstConst{constp->fileline(), num}; @@ -6057,7 +6243,8 @@ private: void checkClassAssign(AstNode* nodep, const char* side, AstNode* rhsp, AstNodeDType* lhsDTypep) { - if (VN_IS(lhsDTypep, ClassRefDType) && !VN_IS(rhsp->dtypep(), ClassRefDType)) { + if (VN_IS(lhsDTypep, ClassRefDType) + && !(rhsp->dtypep() && VN_IS(rhsp->dtypep()->skipRefp(), ClassRefDType))) { if (auto* const constp = VN_CAST(rhsp, Const)) { if (constp->num().isNull()) return; } @@ -6226,15 +6413,16 @@ private: if (bad) { { // if (warnOn), but not needed here if (debug() > 4) nodep->backp()->dumpTree("- back: "); - nodep->v3warn(WIDTH, "Logical operator " - << nodep->prettyTypeName() << " expects 1 bit on the " - << side << ", but " << side << "'s " - << underp->prettyTypeName() << " generates " - << underp->width() - << (underp->width() != underp->widthMin() - ? " or " + cvtToStr(underp->widthMin()) - : "") - << " bits."); + nodep->v3widthWarn(1, underp->width(), + "Logical operator " + << nodep->prettyTypeName() << " expects 1 bit on the " + << side << ", but " << side << "'s " + << underp->prettyTypeName() << " generates " + << underp->width() + << (underp->width() != underp->widthMin() + ? " or " + cvtToStr(underp->widthMin()) + : "") + << " bits."); } VL_DO_DANGLING(fixWidthReduce(VN_AS(underp, NodeExpr)), underp); // Changed } @@ -6281,8 +6469,8 @@ private: if (const AstEnumDType* const expEnump = VN_CAST(expDTypep->skipRefToEnump(), EnumDType)) { const auto castable = computeCastable(expEnump, underp->dtypep(), underp); - if (castable != COMPATIBLE && castable != ENUM_IMPLICIT && !VN_IS(underp, Cast) - && !VN_IS(underp, CastDynamic) && !m_enumItemp + if (castable != SAMEISH && castable != COMPATIBLE && castable != ENUM_IMPLICIT + && !VN_IS(underp, Cast) && !VN_IS(underp, CastDynamic) && !m_enumItemp && !nodep->fileline()->warnIsOff(V3ErrorCode::ENUMVALUE) && warnOn) { underp->v3warn(ENUMVALUE, "Implicit conversion to enum " @@ -6408,16 +6596,18 @@ private: } if (bad && warnOn) { if (debug() > 4) nodep->backp()->dumpTree("- back: "); - nodep->v3warn( - WIDTH, ucfirst(nodep->prettyOperatorName()) - << " expects " << expWidth - << (expWidth != expWidthMin ? " or " + cvtToStr(expWidthMin) : "") - << " bits on the " << side << ", but " << side << "'s " - << underp->prettyTypeName() << " generates " << underp->width() - << (underp->width() != underp->widthMin() - ? " or " + cvtToStr(underp->widthMin()) - : "") - << " bits."); + + nodep->v3widthWarn( + expWidth, underp->width(), + ucfirst(nodep->prettyOperatorName()) + << " expects " << expWidth + << (expWidth != expWidthMin ? " or " + cvtToStr(expWidthMin) : "") + << " bits on the " << side << ", but " << side << "'s " + << underp->prettyTypeName() << " generates " << underp->width() + << (underp->width() != underp->widthMin() + ? " or " + cvtToStr(underp->widthMin()) + : "") + << " bits."); } if (bad || underp->width() != expWidth) { // If we're in an NodeAssign, don't truncate the RHS if the LHS is @@ -7013,10 +7203,11 @@ private: const Castable castable = UNSUPPORTED; toDtp = toDtp->skipRefToEnump(); fromDtp = fromDtp->skipRefToEnump(); - if (toDtp == fromDtp) return COMPATIBLE; - + if (toDtp == fromDtp) return SAMEISH; + if (toDtp->similarDType(fromDtp)) return SAMEISH; // UNSUP unpacked struct/unions (treated like BasicDType) const AstNodeDType* fromBaseDtp = computeCastableBase(fromDtp); + const bool fromNumericable = VN_IS(fromBaseDtp, BasicDType) || VN_IS(fromBaseDtp, EnumDType) || VN_IS(fromBaseDtp, NodeUOrStructDType); diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index 785db8add..34cc4c689 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -214,8 +214,9 @@ private: void visit(AstNodeFTask* nodep) override { iterateChildren(nodep); editDType(nodep); - if (nodep->classMethod() && nodep->pureVirtual() && VN_IS(m_modp, Class) - && !VN_AS(m_modp, Class)->isVirtual()) { + AstClass* classp = VN_CAST(m_modp, Class); + if (nodep->classMethod() && nodep->pureVirtual() && classp && !classp->isInterfaceClass() + && !classp->isVirtual()) { nodep->v3error( "Illegal to have 'pure virtual' in non-virtual class (IEEE 1800-2017 8.21)"); } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index 76956b5e8..7ee1fb9e1 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -26,7 +26,6 @@ #include "V3CUse.h" #include "V3Case.h" #include "V3Cast.h" -#include "V3Cdc.h" #include "V3Class.h" #include "V3Clean.h" #include "V3Clock.h" @@ -90,6 +89,7 @@ #include "V3TSP.h" #include "V3Table.h" #include "V3Task.h" +#include "V3ThreadPool.h" #include "V3Timing.h" #include "V3Trace.h" #include "V3TraceDecl.h" @@ -371,13 +371,6 @@ static void process() { V3Const::constifyAll(v3Global.rootp()); V3Dead::deadifyAllScoped(v3Global.rootp()); - // Clock domain crossing analysis - if (v3Global.opt.cdc()) { - V3Cdc::cdcAll(v3Global.rootp()); - V3Error::abortIfErrors(); - return; - } - // Reorder assignments in pipelined blocks if (v3Global.opt.fReorder()) V3Split::splitReorderAll(v3Global.rootp()); @@ -578,8 +571,6 @@ static void process() { if (v3Global.opt.cmake()) V3EmitCMake::emit(); if (v3Global.opt.gmake()) V3EmitMk::emitmk(); } - - // Note early return above when opt.cdc() } static void verilate(const string& argString) { @@ -600,6 +591,9 @@ static void verilate(const string& argString) { v3fatalSrc("VERILATOR_DEBUG_SKIP_IDENTICAL w/ --skip-identical: Changes found\n"); } // LCOV_EXCL_STOP + // Adjust thread pool size + V3ThreadPool::s().resize(v3Global.opt.verilateJobs()); + // --FRONTEND------------------ // Cleanup @@ -619,6 +613,7 @@ static void verilate(const string& argString) { V3Partition::selfTest(); V3Partition::selfTestNormalizeCosts(); V3Broken::selfTest(); + V3ThreadPool::selfTest(); } // Read first filename diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp index 78291e3e6..f6352cb03 100644 --- a/src/VlcMain.cpp +++ b/src/VlcMain.cpp @@ -58,13 +58,14 @@ void VlcOptions::parseOptsList(int argc, char** argv) { V3OptionParser::AppendHelper DECL_OPTION{parser}; V3OPTION_PARSER_DECL_TAGS; - DECL_OPTION("-annotate-all", OnOff, &m_annotateAll); - DECL_OPTION("-rank", OnOff, &m_rank); - DECL_OPTION("-unlink", OnOff, &m_unlink); - DECL_OPTION("-annotate-min", Set, &m_annotateMin); DECL_OPTION("-annotate", Set, &m_annotateOut); + DECL_OPTION("-annotate-all", OnOff, &m_annotateAll); + DECL_OPTION("-annotate-min", Set, &m_annotateMin); + DECL_OPTION("-annotate-points", OnOff, &m_annotatePoints); DECL_OPTION("-debug", CbCall, []() { V3Error::debugDefault(3); }); DECL_OPTION("-debugi", CbVal, [](int v) { V3Error::debugDefault(v); }); + DECL_OPTION("-rank", OnOff, &m_rank); + DECL_OPTION("-unlink", OnOff, &m_unlink); DECL_OPTION("-V", CbCall, []() { showVersion(true); std::exit(0); diff --git a/src/VlcOptions.h b/src/VlcOptions.h index c105594d4..5bfd183f5 100644 --- a/src/VlcOptions.h +++ b/src/VlcOptions.h @@ -37,6 +37,7 @@ class VlcOptions final { string m_annotateOut; // main switch: --annotate I bool m_annotateAll = false; // main switch: --annotate-all int m_annotateMin = 10; // main switch: --annotate-min I + bool m_annotatePoints = false; // main switch: --annotate-points VlStringSet m_readFiles; // main switch: --read bool m_rank = false; // main switch: --rank bool m_unlink = false; // main switch: --unlink @@ -62,6 +63,7 @@ public: string annotateOut() const { return m_annotateOut; } bool annotateAll() const { return m_annotateAll; } int annotateMin() const { return m_annotateMin; } + bool annotatePoints() const { return m_annotatePoints; } bool rank() const { return m_rank; } bool unlink() const { return m_unlink; } string writeFile() const { return m_writeFile; } diff --git a/src/VlcPoint.h b/src/VlcPoint.h index bb954bf36..f2ed5b287 100644 --- a/src/VlcPoint.h +++ b/src/VlcPoint.h @@ -54,6 +54,11 @@ public: void countInc(uint64_t inc) { m_count += inc; } uint64_t count() const { return m_count; } void testsCoveringInc() { m_testsCovering++; } + bool ok(unsigned annotateMin) const { + const std::string threshStr = thresh(); + unsigned threshi = !threshStr.empty() ? std::atoi(threshStr.c_str()) : annotateMin; + return m_count >= threshi; + } // KEY ACCESSORS string filename() const { return keyExtract(VL_CIK_FILENAME); } string comment() const { return keyExtract(VL_CIK_COMMENT); } @@ -79,15 +84,21 @@ public: } return ""; } - static void dumpHeader() { - cout << "Points:\n"; - cout << " Num, TestsCover, Count, Name\n"; + static void dumpHeader(std::ostream& os) { + os << "Points:\n"; + os << " Num, TestsCover, Count, Name\n"; } - void dump() const { - cout << " " << std::setw(8) << std::setfill('0') << pointNum(); - cout << ", " << std::setw(7) << std::setfill(' ') << testsCovering(); - cout << ", " << std::setw(7) << std::setfill(' ') << count(); - cout << ", \"" << name() << "\"\n"; + void dump(std::ostream& os) const { + os << " " << std::setw(8) << std::setfill('0') << pointNum(); + os << ", " << std::setw(7) << std::setfill(' ') << testsCovering(); + os << ", " << std::setw(7) << std::setfill(' ') << count(); + os << ", \"" << name() << "\"\n"; + } + void dumpAnnotate(std::ostream& os, unsigned annotateMin) const { + os << (ok(annotateMin) ? "+" : "-"); + os << std::setw(6) << std::setfill('0') << count(); + os << " point: comment=" << comment(); + os << "\n"; } }; @@ -118,10 +129,10 @@ public: // METHODS void dump() { UINFO(2, "dumpPoints...\n"); - VlcPoint::dumpHeader(); + VlcPoint::dumpHeader(cout); for (const auto& i : *this) { const VlcPoint& point = pointNumber(i.second); - point.dump(); + point.dump(cout); } } VlcPoint& pointNumber(uint64_t num) { return m_points[num]; } diff --git a/src/VlcSource.h b/src/VlcSource.h index 5c4eedf04..f08188e1e 100644 --- a/src/VlcSource.h +++ b/src/VlcSource.h @@ -21,38 +21,49 @@ #include "verilatedos.h" #include +#include #include #include +class VlcPoint; + //******************************************************************** // VlcColumnCount - count at specific source file, line and column class VlcSourceCount final { private: + // TYPES + using PointsSet = std::set; + // MEMBERS int m_lineno; ///< Line number - int m_column; ///< Column number uint64_t m_count = 0; ///< Count bool m_ok = false; ///< Coverage is above threshold + PointsSet m_points; // Points on this line public: // CONSTRUCTORS - VlcSourceCount(int lineno, int column) - : m_lineno{lineno} - , m_column{column} {} + VlcSourceCount(int lineno) + : m_lineno{lineno} {} ~VlcSourceCount() = default; // ACCESSORS int lineno() const { return m_lineno; } - int column() const { return m_column; } uint64_t count() const { return m_count; } bool ok() const { return m_ok; } // METHODS void incCount(uint64_t count, bool ok) { - m_count += count; - if (ok) m_ok = true; + if (!m_count) { + m_count = count; + m_ok = ok; + } else { + m_count = std::min(m_count, count); + if (!ok) m_ok = false; + } } + void insertPoint(const VlcPoint* pointp) { m_points.emplace(pointp); } + PointsSet& points() { return m_points; } }; //******************************************************************** @@ -61,8 +72,7 @@ public: class VlcSource final { public: // TYPES - using ColumnMap = std::map; // Map of {column} - using LinenoMap = std::map; // Map of {lineno}{column} + using LinenoMap = std::map; // Map of {column} private: // MEMBERS @@ -83,16 +93,13 @@ public: LinenoMap& lines() { return m_lines; } // METHODS - void incCount(int lineno, int column, uint64_t count, bool ok) { - LinenoMap::iterator lit = m_lines.find(lineno); - if (lit == m_lines.end()) lit = m_lines.insert(std::make_pair(lineno, ColumnMap())).first; - ColumnMap& cmap = lit->second; - ColumnMap::iterator cit = cmap.find(column); - if (cit == cmap.end()) { - cit = cmap.insert(std::make_pair(column, VlcSourceCount{lineno, column})).first; - } - VlcSourceCount& sc = cit->second; + void lineIncCount(int lineno, uint64_t count, bool ok, const VlcPoint* pointp) { + auto lit = m_lines.find(lineno); + if (lit == m_lines.end()) + lit = m_lines.emplace(std::make_pair(lineno, VlcSourceCount{lineno})).first; + VlcSourceCount& sc = lit->second; sc.incCount(count, ok); + sc.insertPoint(pointp); } }; diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index db5a9fa03..728813622 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -116,20 +116,8 @@ void VlcTop::writeInfo(const string& filename) { os << "SF:" << source.name() << '\n'; VlcSource::LinenoMap& lines = source.lines(); for (auto& li : lines) { - const int lineno = li.first; - VlcSource::ColumnMap& cmap = li.second; - bool first = true; - uint64_t min_count = 0; // Minimum across all columns on line - for (auto& ci : cmap) { - VlcSourceCount& col = ci.second; - if (first) { - min_count = col.count(); - first = false; - } else { - min_count = std::min(min_count, col.count()); - } - } - os << "DA:" << lineno << "," << min_count << "\n"; + const VlcSourceCount& sc = li.second; + os << "DA:" << sc.lineno() << "," << sc.count() << "\n"; } os << "end_of_record\n"; } @@ -206,14 +194,11 @@ void VlcTop::annotateCalc() { const int lineno = point.lineno(); if (!filename.empty() && lineno != 0) { VlcSource& source = sources().findNewSource(filename); - const string threshStr = point.thresh(); - unsigned thresh - = (!threshStr.empty()) ? std::atoi(threshStr.c_str()) : opt.annotateMin(); - const bool ok = (point.count() >= thresh); + const bool ok = point.ok(opt.annotateMin()); UINFO(9, "AnnoCalc count " << filename << ":" << lineno << ":" << point.column() << " " << point.count() << " " << point.linescov() << '\n'); // Base coverage - source.incCount(lineno, point.column(), point.count(), ok); + source.lineIncCount(lineno, point.count(), ok, &point); // Additional lines covered by this statement bool range = false; int start = 0; @@ -222,7 +207,7 @@ void VlcTop::annotateCalc() { for (const char* covp = linescov.c_str(); true; ++covp) { if (!*covp || *covp == ',') { // Ending for (int lni = start; start && lni <= end; ++lni) { - source.incCount(lni, point.column(), point.count(), ok); + source.lineIncCount(lni, point.count(), ok, &point); } if (!*covp) break; start = 0; // Prep for next @@ -253,16 +238,13 @@ void VlcTop::annotateCalcNeeded() { if (opt.annotateAll()) source.needed(true); VlcSource::LinenoMap& lines = source.lines(); for (auto& li : lines) { - VlcSource::ColumnMap& cmap = li.second; - for (auto& ci : cmap) { - VlcSourceCount& col = ci.second; - // UINFO(0,"Source "<second; - for (auto& ci : cmap) { - VlcSourceCount& col = ci.second; - // UINFO(0,"Source - // "<second; + // UINFO(0,"Source + // "<dumpAnnotate(os, opt.annotateMin()); } } - - if (first) os << "\t" << line << '\n'; } } } diff --git a/src/verilog.l b/src/verilog.l index bff9bd3b1..7793e2205 100644 --- a/src/verilog.l +++ b/src/verilog.l @@ -236,6 +236,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$fwriteb" { FL; return yD_FWRITEB; } "$fwriteh" { FL; return yD_FWRITEH; } "$fwriteo" { FL; return yD_FWRITEO; } + "$global_clock" { FL; return yD_GLOBAL_CLOCK; } "$hold" { FL; return yaTIMINGSPEC; } "$hypot" { FL; return yD_HYPOT; } "$itor" { FL; return yD_ITOR; } @@ -459,12 +460,14 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* System Tasks */ "$bits" { FL; return yD_BITS; } "$changed" { FL; return yD_CHANGED; } + "$changed_gclk" { FL; return yD_CHANGED_GCLK; } "$countbits" { FL; return yD_COUNTBITS; } "$countones" { FL; return yD_COUNTONES; } "$dimensions" { FL; return yD_DIMENSIONS; } "$error" { FL; return yD_ERROR; } "$fatal" { FL; return yD_FATAL; } "$fell" { FL; return yD_FELL; } + "$fell_gclk" { FL; return yD_FELL_GCLK; } "$high" { FL; return yD_HIGH; } "$increment" { FL; return yD_INCREMENT; } "$info" { FL; return yD_INFO; } @@ -478,8 +481,10 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "$right" { FL; return yD_RIGHT; } "$root" { FL; return yD_ROOT; } "$rose" { FL; return yD_ROSE; } + "$rose_gclk" { FL; return yD_ROSE_GCLK; } "$size" { FL; return yD_SIZE; } "$stable" { FL; return yD_STABLE; } + "$stable_gclk" { FL; return yD_STABLE_GCLK; } "$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; } "$warning" { FL; return yD_WARNING; } /* SV2005 Keywords */ @@ -518,7 +523,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "endpackage" { FL; return yENDPACKAGE; } "endprogram" { FL; return yENDPROGRAM; } "endproperty" { FL; return yENDPROPERTY; } - "endsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "endsequence" { FL; return yENDSEQUENCE; } "enum" { FL; return yENUM; } "expect" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "export" { FL; return yEXPORT; } @@ -555,7 +560,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "randc" { FL; return yRANDC; } "randcase" { FL; return yRANDCASE; } "randomize" { FL; return yRANDOMIZE; } - "randsequence" { ERROR_RSVD_WORD("SystemVerilog 2005"); } + "randsequence" { FL; return yRANDSEQUENCE; } "ref" { FL; return yREF; } "restrict" { FL; return yRESTRICT; } "return" { FL; return yRETURN; } @@ -572,7 +577,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "throughout" { ERROR_RSVD_WORD("SystemVerilog 2005"); } "timeprecision" { FL; return yTIMEPRECISION; } "timeunit" { FL; return yTIMEUNIT; } - "type" { FL; return yTYPE; } + "type" { FL; return yTYPE__LEX; } "typedef" { FL; return yTYPEDEF; } "union" { FL; return yUNION; } "unique" { FL; return yUNIQUE; } @@ -589,8 +594,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} { /* Keywords */ "accept_on" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "checker" { ERROR_RSVD_WORD("SystemVerilog 2009"); } - "endchecker" { ERROR_RSVD_WORD("SystemVerilog 2009"); } + "checker" { FL; return yCHECKER; } + "endchecker" { FL; return yENDCHECKER; } "eventually" { ERROR_RSVD_WORD("SystemVerilog 2009"); } "global" { FL; return yGLOBAL__LEX; } "implies" { ERROR_RSVD_WORD("SystemVerilog 2009"); } @@ -616,8 +621,8 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} { /* Keywords */ "implements" { FL; return yIMPLEMENTS; } - "interconnect" { ERROR_RSVD_WORD("SystemVerilog 2012"); } - "nettype" { ERROR_RSVD_WORD("SystemVerilog 2012"); } + "interconnect" { FL; return yINTERCONNECT; } + "nettype" { FL; return yNETTYPE; } "soft" { FL; return ySOFT; } } @@ -752,9 +757,15 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} "/*verilator parallel_case*/" { FL; return yVL_PARALLEL_CASE; } "/*verilator public*/" { FL; return yVL_PUBLIC; } "/*verilator public_flat*/" { FL; return yVL_PUBLIC_FLAT; } + "/*verilator public_flat_on*/" { FL; return yVL_PUBLIC_FLAT_ON; } "/*verilator public_flat_rd*/" { FL; return yVL_PUBLIC_FLAT_RD; } + "/*verilator public_flat_rd_on*/" { FL; return yVL_PUBLIC_FLAT_RD_ON; } "/*verilator public_flat_rw*/" { FL; return yVL_PUBLIC_FLAT_RW; } // The @(edge) is converted by the preproc + "/*verilator public_flat_rw_on*/" { FL; return yVL_PUBLIC_FLAT_RW_ON; } + "/*verilator public_flat_rw_on_sns*/" { FL; return yVL_PUBLIC_FLAT_RW_ON_SNS; } "/*verilator public_module*/" { FL; return yVL_PUBLIC_MODULE; } + "/*verilator public_on*/" { FL; return yVL_PUBLIC_ON; } + "/*verilator public_off*/" { FL; return yVL_PUBLIC_OFF; } // terminates previous 'verilator public*_on' "/*verilator sc_bv*/" { FL; return yVL_SC_BV; } "/*verilator sc_clock*/" { FL; yylval.fl->v3warn(DEPRECATED, "sc_clock is ignored"); FL_BRK; } "/*verilator sformat*/" { FL; return yVL_SFORMAT; } @@ -899,7 +910,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5} /* "# 1'b0" is a delay value so must lex as "#" "1" "'b0" */ if (PARSEP->lexPrevToken()=='#') { int shortlen = 0; - while (isdigit(yytext[shortlen])) ++shortlen; + while (std::isdigit(yytext[shortlen])) ++shortlen; if (shortlen) { // Push rest past numbers for later parse PARSEP->lexUnputString(yytext + shortlen, yyleng - shortlen); diff --git a/src/verilog.y b/src/verilog.y index bdbd218af..fbf1142a9 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -78,6 +78,7 @@ class V3ParseGrammar { public: AstVar* m_varAttrp = nullptr; // Current variable for attribute adding AstRange* m_gateRangep = nullptr; // Current range for gate declarations + AstNode* m_scopedSigAttr = nullptr; // Pointer to default signal attribute AstCase* m_caseAttrp = nullptr; // Current case statement for attribute adding AstNodeDType* m_varDTypep = nullptr; // Pointer to data type for next signal declaration AstNodeDType* m_memDTypep = nullptr; // Pointer to data type for next member declaration @@ -94,8 +95,9 @@ public: bool m_varDeclTyped = false; // Var got reg/wire for dedup check bool m_pinAnsi = false; // In ANSI port list bool m_tracingParse = true; // Tracing disable for parser + bool m_inImplements = false; // Is inside class implements list bool m_insideProperty = false; // Is inside property declaration - bool m_typedPropertyPort = false; // True if typed property port occurred on port lists + bool m_typedPropertyPort = false; // Typed property port occurred on port lists bool m_modportImpExpActive = false; // Standalone ID is a tf_identifier instead of port_identifier bool m_modportImpExpLastIsExport @@ -168,6 +170,15 @@ public: return new AstGatePin{rangep->fileline(), exprp, rangep->cloneTree(true)}; } } + AstSenTree* createClockSenTree(FileLine* fl, AstNodeExpr* exprp) { + return new AstSenTree{fl, new AstSenItem{fl, VEdgeType::ET_CHANGED, exprp}}; + } + AstNodeExpr* createGlobalClockParseRef(FileLine* fl) { + return new AstParseRef{fl, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr}; + } + AstSenTree* createGlobalClockSenTree(FileLine* fl) { + return createClockSenTree(fl, createGlobalClockParseRef(fl)); + } AstNode* createTypedef(FileLine* fl, const string& name, AstNode* attrsp, AstNodeDType* basep, AstNodeRange* rangep) { AstNode* const nodep = new AstTypedef{fl, name, attrsp, VFlagChildDType{}, @@ -260,6 +271,19 @@ public: } return itemsp; } + + void setScopedSigAttr(AstNode* attrsp) { + if (m_scopedSigAttr) { // clearing set attribute + VL_DO_DANGLING(m_scopedSigAttr->deleteTree(), m_scopedSigAttr); + } + m_scopedSigAttr = attrsp; + } + + void createScopedSigAttr(VAttrType vattrT) { + setScopedSigAttr(new AstAttrOf{PARSEP->lexFileline(), vattrT}); + } + + AstNode* cloneScopedSigAttr() const { return AstNode::cloneTreeNull(m_scopedSigAttr, true); } }; const VBasicDTypeKwd LOGIC = VBasicDTypeKwd::LOGIC; // Shorthand "LOGIC" @@ -334,7 +358,7 @@ int V3ParseGrammar::s_modTypeImpNum = 0; // Apply a strength to a list of nodes under beginp #define STRENGTH_LIST(beginp, strengthSpecNodep, typeToCast) \ { \ - if (AstStrengthSpec* specp = VN_CAST(strengthSpecNodep, StrengthSpec)) { \ + if (AstStrengthSpec* const specp = VN_CAST(strengthSpecNodep, StrengthSpec)) { \ for (auto* nodep = beginp; nodep; nodep = nodep->nextp()) { \ auto* const assignp = VN_AS(nodep, typeToCast); \ assignp->strengthSpecp(nodep == beginp ? specp : specp->cloneTree(false)); \ @@ -538,7 +562,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yCASEX "casex" %token yCASEZ "casez" %token yCHANDLE "chandle" -//UNSUP %token yCHECKER "checker" +%token yCHECKER "checker" %token yCLASS "class" //UNSUP %token yCLOCK "clock" %token yCLOCKING "clocking" @@ -564,7 +588,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yELSE "else" %token yEND "end" %token yENDCASE "endcase" -//UNSUP %token yENDCHECKER "endchecker" +%token yENDCHECKER "endchecker" %token yENDCLASS "endclass" %token yENDCLOCKING "endclocking" %token yENDFUNCTION "endfunction" @@ -576,7 +600,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yENDPRIMITIVE "endprimitive" %token yENDPROGRAM "endprogram" %token yENDPROPERTY "endproperty" -//UNSUP %token yENDSEQUENCE "endsequence" +%token yENDSEQUENCE "endsequence" %token yENDSPECIFY "endspecify" %token yENDTABLE "endtable" %token yENDTASK "endtask" @@ -619,7 +643,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yINSIDE "inside" %token yINT "int" %token yINTEGER "integer" -//UNSUP %token yINTERCONNECT "interconnect" +%token yINTERCONNECT "interconnect" %token yINTERFACE "interface" //UNSUP %token yINTERSECT "intersect" %token yJOIN "join" @@ -637,7 +661,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yMODULE "module" %token yNAND "nand" %token yNEGEDGE "negedge" -//UNSUP %token yNETTYPE "nettype" +%token yNETTYPE "nettype" %token yNEW__ETC "new" %token yNEW__LEX "new-in-lex" %token yNEW__PAREN "new-then-paren" @@ -669,7 +693,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yRANDC "randc" %token yRANDCASE "randcase" %token yRANDOMIZE "randomize" -//UNSUP %token yRANDSEQUENCE "randsequence" +%token yRANDSEQUENCE "randsequence" %token yRCMOS "rcmos" %token yREAL "real" %token yREALTIME "realtime" @@ -733,8 +757,10 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yTRIOR "trior" %token yTRIREG "trireg" %token yTRUE "true" -%token yTYPE "type" %token yTYPEDEF "typedef" +%token yTYPE__EQ "type-then-eqneq" +%token yTYPE__ETC "type" +%token yTYPE__LEX "type-in-lex" %token yUNION "union" %token yUNIQUE "unique" %token yUNIQUE0 "unique0" @@ -784,6 +810,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_CAST "$cast" %token yD_CEIL "$ceil" %token yD_CHANGED "$changed" +%token yD_CHANGED_GCLK "$changed_gclk" %token yD_CLOG2 "$clog2" %token yD_COS "$cos" %token yD_COSH "$cosh" @@ -819,6 +846,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_FDISPLAYH "$fdisplayh" %token yD_FDISPLAYO "$fdisplayo" %token yD_FELL "$fell" +%token yD_FELL_GCLK "$fell_gclk" %token yD_FEOF "$feof" %token yD_FERROR "$ferror" %token yD_FFLUSH "$fflush" @@ -844,6 +872,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_FWRITEB "$fwriteb" %token yD_FWRITEH "$fwriteh" %token yD_FWRITEO "$fwriteo" +%token yD_GLOBAL_CLOCK "$global_clock" %token yD_HIGH "$high" %token yD_HYPOT "$hypot" %token yD_INCREMENT "$increment" @@ -875,6 +904,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_RIGHT "$right" %token yD_ROOT "$root" %token yD_ROSE "$rose" +%token yD_ROSE_GCLK "$rose_gclk" %token yD_RTOI "$rtoi" %token yD_SAMPLED "$sampled" %token yD_SFORMAT "$sformat" @@ -887,6 +917,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_SQRT "$sqrt" %token yD_SSCANF "$sscanf" %token yD_STABLE "$stable" +%token yD_STABLE_GCLK "$stable_gclk" %token yD_STACKTRACE "$stacktrace" %token yD_STIME "$stime" %token yD_STOP "$stop" @@ -922,28 +953,34 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_WRITEMEMH "$writememh" %token yD_WRITEO "$writeo" -%token yVL_CLOCKER "/*verilator clocker*/" -%token yVL_CLOCK_ENABLE "/*verilator clock_enable*/" -%token yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/" -%token yVL_FORCEABLE "/*verilator forceable*/" -%token yVL_FULL_CASE "/*verilator full_case*/" -%token yVL_HIER_BLOCK "/*verilator hier_block*/" -%token yVL_INLINE_MODULE "/*verilator inline_module*/" -%token yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/" -%token yVL_NO_CLOCKER "/*verilator no_clocker*/" -%token yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/" -%token yVL_NO_INLINE_TASK "/*verilator no_inline_task*/" -%token yVL_PARALLEL_CASE "/*verilator parallel_case*/" -%token yVL_PUBLIC "/*verilator public*/" -%token yVL_PUBLIC_FLAT "/*verilator public_flat*/" -%token yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/" -%token yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/" -%token yVL_PUBLIC_MODULE "/*verilator public_module*/" -%token yVL_SC_BV "/*verilator sc_bv*/" -%token yVL_SFORMAT "/*verilator sformat*/" -%token yVL_SPLIT_VAR "/*verilator split_var*/" -%token yVL_TAG "/*verilator tag*/" -%token yVL_TRACE_INIT_TASK "/*verilator trace_init_task*/" +%token yVL_CLOCKER "/*verilator clocker*/" +%token yVL_CLOCK_ENABLE "/*verilator clock_enable*/" +%token yVL_COVERAGE_BLOCK_OFF "/*verilator coverage_block_off*/" +%token yVL_FORCEABLE "/*verilator forceable*/" +%token yVL_FULL_CASE "/*verilator full_case*/" +%token yVL_HIER_BLOCK "/*verilator hier_block*/" +%token yVL_INLINE_MODULE "/*verilator inline_module*/" +%token yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/" +%token yVL_NO_CLOCKER "/*verilator no_clocker*/" +%token yVL_NO_INLINE_MODULE "/*verilator no_inline_module*/" +%token yVL_NO_INLINE_TASK "/*verilator no_inline_task*/" +%token yVL_PARALLEL_CASE "/*verilator parallel_case*/" +%token yVL_PUBLIC "/*verilator public*/" +%token yVL_PUBLIC_FLAT "/*verilator public_flat*/" +%token yVL_PUBLIC_FLAT_ON "/*verilator public_flat_on*/" +%token yVL_PUBLIC_FLAT_RD "/*verilator public_flat_rd*/" +%token yVL_PUBLIC_FLAT_RD_ON "/*verilator public_flat_rd_on*/" +%token yVL_PUBLIC_FLAT_RW "/*verilator public_flat_rw*/" +%token yVL_PUBLIC_FLAT_RW_ON "/*verilator public_flat_rw_on*/" +%token yVL_PUBLIC_FLAT_RW_ON_SNS "/*verilator public_flat_rw_on_sns*/" +%token yVL_PUBLIC_ON "/*verilator public_on*/" +%token yVL_PUBLIC_OFF "/*verilator public_off*/" +%token yVL_PUBLIC_MODULE "/*verilator public_module*/" +%token yVL_SC_BV "/*verilator sc_bv*/" +%token yVL_SFORMAT "/*verilator sformat*/" +%token yVL_SPLIT_VAR "/*verilator split_var*/" +%token yVL_TAG "/*verilator tag*/" +%token yVL_TRACE_INIT_TASK "/*verilator trace_init_task*/" %token yP_TICK "'" %token yP_TICKBRA "'{" @@ -1153,7 +1190,7 @@ description: // ==IEEE: description | package_declaration { } | package_item { if ($1) PARSEP->unitPackage($1->fileline())->addStmtsp($1); } | bind_directive { if ($1) PARSEP->unitPackage($1->fileline())->addStmtsp($1); } - // unsupported // IEEE: config_declaration + //UNSUP config_declaration { } // // Verilator only | yaT_RESETALL { } // Else, under design, and illegal based on IEEE 22.3 | yaT_NOUNCONNECTED { PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE); } @@ -1218,6 +1255,7 @@ package_item: // ==IEEE: package_item | anonymous_program { $$ = $1; } | package_export_declaration { $$ = $1; } | timeunits_declaration { $$ = $1; } + | sigAttrScope { $$ = nullptr; } ; package_or_generate_item_declaration: // ==IEEE: package_or_generate_item_declaration @@ -1225,9 +1263,9 @@ package_or_generate_item_declaration: // ==IEEE: package_or_generate_i | data_declaration { $$ = $1; } | task_declaration { $$ = $1; } | function_declaration { $$ = $1; } - //UNSUP checker_declaration { $$ = $1; } + | checker_declaration { $$ = $1; } | dpi_import_export { $$ = $1; } - //UNSUP extern_constraint_declaration { $$ = $1; } + | extern_constraint_declaration { $$ = $1; } | class_declaration { $$ = $1; } // // class_constructor_declaration is part of function_declaration // // local_parameter_declaration under parameter_declaration @@ -1329,6 +1367,7 @@ modFront: PARSEP->rootp()->addModulesp($$); SYMP->pushNew($$); GRAMMARP->m_modp = $$; } + | modFront sigAttrScope { $$ = $1; } ; importsAndParametersE: // IEEE: common part of module_declaration, interface_declaration, program_declaration @@ -1355,7 +1394,7 @@ parameter_value_assignmentE: // IEEE: [ parameter_value_assignment ] ; parameter_value_assignment: // IEEE: parameter_value_assignment - '#' '(' cellparamList ')' { $$ = $3; } + '#' '(' cellparamListE ')' { $$ = $3; } // // Parentheses are optional around a single parameter | '#' yaINTNUM { $$ = new AstPin{$2, 1, "", new AstConst{$2, *$2}}; } | '#' yaFLOATNUM { $$ = new AstPin{$2, 1, "", @@ -1369,7 +1408,7 @@ parameter_value_assignment: // IEEE: parameter_value_assignment parameter_value_assignmentClass: // IEEE: [ parameter_value_assignment ] (for classes) // // Like parameter_value_assignment, but for classes only, which always have #() - '#' '(' cellparamList ')' { $$ = $3; } + '#' '(' cellparamListE ')' { $$ = $3; } ; parameter_port_listE: // IEEE: parameter_port_list + empty == parameter_value_assignment @@ -1387,13 +1426,18 @@ parameter_port_listE: // IEEE: parameter_port_list + empty == paramete paramPortDeclOrArgList: // IEEE: list_of_param_assignments + { parameter_port_declaration } paramPortDeclOrArg { $$ = $1; } | paramPortDeclOrArgList ',' paramPortDeclOrArg { $$ = $1->addNext($3); } + | paramPortDeclOrArgList sigAttrScope {$$ = $1;} ; paramPortDeclOrArg: // IEEE: param_assignment + parameter_port_declaration // // We combine the two as we can't tell which follows a comma + paramPortDeclOrArgSub {$$ = $1;} + | vlTag { $$ = nullptr; } + ; +paramPortDeclOrArgSub: parameter_port_declarationFrontE param_assignment { $$ = $2; } | parameter_port_declarationTypeFrontE type_assignment { $$ = $2; } - | vlTag { $$ = nullptr; } + | sigAttrScope paramPortDeclOrArgSub {$$ = $2; } ; portsStarE: // IEEE: .* + list_of_ports + list_of_port_declarations + empty @@ -1411,7 +1455,7 @@ list_of_portsE: // IEEE: list_of_ports + list_of_port_declaratio list_of_ports: // IEEE: list_of_ports + list_of_port_declarations portAndTag { $$ = $1; } - | list_of_portsE ',' portAndTagE { $$ = addNextNull($1, $3); } + | list_of_portsE ',' portAndTagE { $$ = addNextNull($1, $3); } ; portAndTagE: @@ -1429,11 +1473,13 @@ portAndTagE: $$ = $$->addNext(varp); $$->v3warn(NULLPORT, "Null port on module (perhaps extraneous comma)"); } | portAndTag { $$ = $1; } + | portAndTag sigAttrScope { $$ = $1; } ; portAndTag: port { $$ = $1; } | vlTag port { $$ = $2; } // Tag will associate with previous port + | sigAttrScope portAndTag { $$ = $2; } ; port: // ==IEEE: port @@ -1461,6 +1507,14 @@ port: // ==IEEE: port | portDirNetE yINTERFACE '.' idAny/*modport*/ portSig rangeListE sigAttrListE { $$ = nullptr; BBUNSUP($2, "Unsupported: generic interfaces"); } // + | portDirNetE yINTERCONNECT signingE rangeListE portSig variable_dimensionListE sigAttrListE + { $$ = $5; + BBUNSUP($2, "Unsupported: interconnect"); + AstNodeDType* const dtp = GRAMMARP->addRange( + new AstBasicDType{$2, LOGIC_IMPLICIT, $3}, $4, true); + VARDTYPE(dtp); + addNextNull($$, VARDONEP($$, $6, $7)); } + // // // IEEE: ansi_port_declaration, with [port_direction] removed // // IEEE: [ net_port_header | interface_port_header ] // // port_identifier { unpacked_dimension } [ '=' constant_expression ] @@ -1582,6 +1636,7 @@ intFront: $$->lifetime($2); PARSEP->rootp()->addModulesp($$); SYMP->pushNew($$); } + | intFront sigAttrScope { $$ = $1; } ; interface_itemListE: @@ -1779,8 +1834,8 @@ modportPortsDecl: modportSimplePortOrTFPort:// IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier id { $$ = $1; } - //UNSUP '.' idAny '(' ')' { } - //UNSUP '.' idAny '(' expr ')' { } + | '.' idAny '(' ')' { $$ = $2; BBUNSUP($1, "Unsupported: Modport dotted port name"); } + | '.' idAny '(' expr ')' { $$ = $2; BBUNSUP($1, "Unsupported: Modport dotted port name"); } ; //************************************************ // Variable Declarations @@ -1820,7 +1875,7 @@ parameter_declarationFront: // IEEE: local_ or parameter_declaration w/o ass parameter_declarationTypeFront: // IEEE: local_ or parameter_declaration w/o assignment // // Front must execute first so VARDTYPE is ready before list of vars - varParamReset yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); } + varParamReset yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); } ; parameter_port_declarationFrontE: // IEEE: local_ or parameter_port_declaration w/o assignment @@ -1829,7 +1884,11 @@ parameter_port_declarationFrontE: // IEEE: local_ or parameter_port_declaration // // Front must execute first so VARDTYPE is ready before list of vars varParamReset implicit_typeE { /*VARRESET-in-varParam*/ VARDTYPE($2); } | varParamReset data_type { /*VARRESET-in-varParam*/ VARDTYPE($2); } - | implicit_typeE { /*VARRESET-in-varParam*/ VARDTYPE($1); } + | implicit_typeE + { /*VARRESET-in-varParam*/ + // Keep previous type to handle subsequent declarations. + // This rule is also used when the previous parameter is a type parameter + } | data_type { /*VARRESET-in-varParam*/ VARDTYPE($1); } ; @@ -1837,8 +1896,8 @@ parameter_port_declarationTypeFrontE: // IEEE: parameter_port_declaration w/o as // // IEEE: parameter_declaration (minus assignment) // // IEEE: local_parameter_declaration (minus assignment) // // Front must execute first so VARDTYPE is ready before list of vars - varParamReset yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); } - | yTYPE { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$1}); } + varParamReset yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$2}); } + | yTYPE__ETC { /*VARRESET-in-varParam*/ VARDTYPE(new AstParseTypeDType{$1}); } ; net_declaration: // IEEE: net_declaration - excluding implict @@ -1854,7 +1913,12 @@ net_declarationFront: // IEEE: beginning of net_declaration { VARDTYPE_NDECL($5); GRAMMARP->setNetStrength(VN_CAST($3, StrengthSpec)); } - //UNSUP net_declRESET yINTERCONNECT signingE rangeListE { VARNET($2); VARDTYPE(x); } + | net_declRESET yINTERCONNECT signingE rangeListE + { BBUNSUP($2, "Unsupported: interconnect"); + VARDECL(WIRE); + AstNodeDType* const dtp = GRAMMARP->addRange( + new AstBasicDType{$2, LOGIC_IMPLICIT, $3}, $4, true); + VARDTYPE_NDECL(dtp); } ; net_declRESET: @@ -2060,7 +2124,7 @@ data_typeNoRef: // ==IEEE: data_type, excluding class_ty { $$ = new AstBasicDType{$1, VBasicDTypeKwd::CHANDLE}; } | yEVENT { $$ = new AstBasicDType{$1, VBasicDTypeKwd::EVENT}; v3Global.setHasEvents(); } - | type_reference { $$ = $1; } + | type_referenceDecl { $$ = $1; } // // IEEE: class_scope: see data_type above // // IEEE: class_type: see data_type above // // IEEE: ps_covergroup: see data_type above @@ -2083,7 +2147,9 @@ data_typeVirtual: // ==IEEE: data_type after yVIRTUAL [ yI data_type_or_void: // ==IEEE: data_type_or_void data_type { $$ = $1; } - //UNSUP yVOID { UNSUP } // No yTAGGED structures + | yVOID + { $$ = new AstBasicDType{$1, LOGIC_IMPLICIT}; + BBUNSUP($1, "Unsupported: void (for tagged unions)"); } ; var_data_type: // ==IEEE: var_data_type @@ -2092,11 +2158,21 @@ var_data_type: // ==IEEE: var_data_type | yVAR implicit_typeE { $$ = $2; } ; -type_reference: // ==IEEE: type_reference - yTYPE '(' exprOrDataType ')' +type_referenceBoth: // IEEE: type_reference + yTYPE__ETC '(' exprOrDataType ')' + { $$ = new AstAttrOf{$1, VAttrType::TYPEID, $3}; } + ; + +type_referenceDecl: // IEEE: type_reference (as a data type for declaration) + yTYPE__ETC '(' exprOrDataType ')' { $$ = new AstRefDType{$1, AstRefDType::FlagTypeOfExpr{}, $3}; } ; +type_referenceEq: // IEEE: type_reference (as an ==/!== expression) + yTYPE__EQ '(' exprOrDataType ')' + { $$ = new AstAttrOf{$1, VAttrType::TYPEID, $3}; } + ; + struct_unionDecl: // IEEE: part of data_type // // packedSigningE is NOP for unpacked ySTRUCT packedSigningE '{' @@ -2134,13 +2210,16 @@ member_decl_assignment: // Derived from IEEE: variable_decl_assi // // So this is different from variable_decl_assignment id variable_dimensionListE { $$ = new AstMemberDType{$1, *$1, VFlagChildDType{}, - GRAMMARP->createArray(AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true), $2, false)}; + GRAMMARP->createArray(AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true), $2, false), + nullptr}; PARSEP->tagNodep($$); - } + } | id variable_dimensionListE '=' variable_declExpr - { BBUNSUP($4, "Unsupported: Initial values in struct/union members."); - // But still need error if packed according to IEEE 7.2.2 - $$ = nullptr; } + { $$ = new AstMemberDType{$1, *$1, VFlagChildDType{}, + GRAMMARP->createArray(AstNodeDType::cloneTreeNull(GRAMMARP->m_memDTypep, true), $2, false), + $4}; + PARSEP->tagNodep($$); + } | idSVKwd { $$ = nullptr; } // // // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]" @@ -2319,7 +2398,7 @@ data_declaration: // ==IEEE: data_declaration // // "yVIRTUAL yID yID" looks just like a data_declaration // // Therefore the virtual_interface_declaration term isn't used // // 1800-2009: - //UNSUP net_type_declaration { $$ = $1; } + | net_type_declaration { $$ = $1; } | vlTag { $$ = nullptr; } ; @@ -2411,12 +2490,15 @@ data_declarationVarFrontClass: // IEEE: part of data_declaration (for class_pro // // = class_new is in variable_decl_assignment ; -//UNSUPnet_type_declaration: // IEEE: net_type_declaration -//UNSUP yNETTYPE data_type idAny/*net_type_identifier*/ ';' { } -//UNSUP // // package_scope part of data_type -//UNSUP | yNETTYPE data_type idAny yWITH__ETC packageClassScope id/*tf_identifier*/ ';' { } -//UNSUP | yNETTYPE packageClassScope id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' { } -//UNSUP ; +net_type_declaration: // IEEE: net_type_declaration + yNETTYPE data_type idAny/*net_type_identifier*/ ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); } + // // package_scope part of data_type + | yNETTYPE data_type idAny yWITH__ETC packageClassScopeE id/*tf_identifier*/ ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); } + | yNETTYPE packageClassScopeE id/*net_type_identifier*/ idAny/*net_type_identifier*/ ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: nettype"); } + ; implicit_typeE: // IEEE: part of *data_type_or_implicit // // Also expanded in data_declaration @@ -2565,20 +2647,23 @@ module_common_item: // ==IEEE: module_common_item { $$ = nullptr; BBUNSUP($1, "Unsupported: alias statements"); } | initial_construct { $$ = $1; } | final_construct { $$ = $1; } - // // IEEE: always_construct - // // Verilator only - event_control attached to always - | yALWAYS stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS, nullptr, $2}; } - | yALWAYS_FF stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_FF, nullptr, $2}; } - | yALWAYS_LATCH stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_LATCH, nullptr, $2}; } - | yALWAYS_COMB stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_COMB, nullptr, $2}; } - // + | always_construct { $$ = $1; } | loop_generate_construct { $$ = $1; } | conditional_generate_construct { $$ = $1; } | elaboration_system_task { $$ = $1; } + | sigAttrScope { $$ = nullptr; } // | error ';' { $$ = nullptr; } ; +always_construct: // IEEE: == always_construct + // // Verilator only - event_control attached to always + yALWAYS stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS, nullptr, $2}; } + | yALWAYS_FF stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_FF, nullptr, $2}; } + | yALWAYS_LATCH stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_LATCH, nullptr, $2}; } + | yALWAYS_COMB stmtBlock { $$ = new AstAlways{$1, VAlwaysKwd::ALWAYS_COMB, nullptr, $2}; } + ; + continuous_assign: // IEEE: continuous_assign yASSIGN driveStrengthE delay_controlE assignList ';' { @@ -2602,7 +2687,8 @@ module_or_generate_item_declaration: // ==IEEE: module_or_generate_it | clocking_declaration { $$ = $1; } | yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { $$ = nullptr; BBUNSUP($1, "Unsupported: default clocking identifier"); } - //UNSUP yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } + | yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: default disable iff"); } ; aliasEqList: // IEEE: part of net_alias @@ -2651,17 +2737,21 @@ generate_region: // ==IEEE: generate_region | yGENERATE yENDGENERATE { $$ = nullptr; } ; -//UNSUPc_generate_region: // IEEE: generate_region (for checkers) -//UNSUP BISONPRE_COPY(generate_region,{s/~c~/c_/g}) // {copied} -//UNSUP ; +c_generate_region: // IEEE: generate_region (for checkers) + BISONPRE_COPY(generate_region,{s/~c~/c_/g}) // {copied} + ; generate_block_or_null: // IEEE: generate_block_or_null (called from gencase/genif/genfor) // ';' // is included in // // IEEE: generate_block // // Must always return a BEGIN node, or nullptr - see GenFor construction - generate_item + ~c~generate_item { $$ = $1 ? (new AstBegin{$1->fileline(), "", $1, true, true}) : nullptr; } - | genItemBegin { $$ = $1; } + | ~c~genItemBegin { $$ = $1; } + ; + +c_generate_block_or_null: // IEEE: generate_block_or_null (for checkers) + BISONPRE_COPY(generate_block_or_null,{s/~c~/c_/g}) // {copied} ; genItemBegin: // IEEE: part of generate_block @@ -2679,27 +2769,27 @@ genItemBegin: // IEEE: part of generate_block { $$ = nullptr; GRAMMARP->endLabel($5, *$3, $5); } ; -//UNSUPc_genItemBegin: // IEEE: part of generate_block (for checkers) -//UNSUP BISONPRE_COPY(genItemBegin,{s/~c~/c_/g}) // {copied} -//UNSUP ; +c_genItemBegin: // IEEE: part of generate_block (for checkers) + BISONPRE_COPY(genItemBegin,{s/~c~/c_/g}) // {copied} + ; genItemOrBegin: // Not in IEEE, but our begin isn't under generate_item ~c~generate_item { $$ = $1; } | ~c~genItemBegin { $$ = $1; } ; -//UNSUPc_genItemOrBegin: // (for checkers) -//UNSUP BISONPRE_COPY(genItemOrBegin,{s/~c~/c_/g}) // {copied} -//UNSUP ; +c_genItemOrBegin: // (for checkers) + BISONPRE_COPY(genItemOrBegin,{s/~c~/c_/g}) // {copied} + ; genItemList: ~c~genItemOrBegin { $$ = $1; } | ~c~genItemList ~c~genItemOrBegin { $$ = addNextNull($1, $2); } ; -//UNSUPc_genItemList: // (for checkers) -//UNSUP BISONPRE_COPY(genItemList,{s/~c~/c_/g}) // {copied} -//UNSUP ; +c_genItemList: // (for checkers) + BISONPRE_COPY(genItemList,{s/~c~/c_/g}) // {copied} + ; generate_item: // IEEE: module_or_interface_or_generate_item // // Only legal when in a generate under a module (or interface under a module) @@ -2711,22 +2801,22 @@ generate_item: // IEEE: module_or_interface_or_generate_item // // so below in c_generate_item ; -//UNSUPc_generate_item: // IEEE: generate_item (for checkers) -//UNSUP checker_or_generate_item { $$ = $1; } -//UNSUP ; +c_generate_item: // IEEE: generate_item (for checkers) + checker_or_generate_item { $$ = $1; } + ; conditional_generate_construct: // ==IEEE: conditional_generate_construct - yCASE '(' expr ')' ~c~case_generate_itemListE yENDCASE + yCASE '(' exprTypeCompare ')' ~c~case_generate_itemListE yENDCASE { $$ = new AstGenCase{$1, $3, $5}; } - | yIF '(' expr ')' ~c~generate_block_or_null %prec prLOWER_THAN_ELSE + | yIF '(' exprTypeCompare ')' ~c~generate_block_or_null %prec prLOWER_THAN_ELSE { $$ = new AstGenIf{$1, $3, $5, nullptr}; } - | yIF '(' expr ')' ~c~generate_block_or_null yELSE ~c~generate_block_or_null + | yIF '(' exprTypeCompare ')' ~c~generate_block_or_null yELSE ~c~generate_block_or_null { $$ = new AstGenIf{$1, $3, $5, $7}; } ; -//UNSUPc_conditional_generate_construct: // IEEE: conditional_generate_construct (for checkers) -//UNSUP BISONPRE_COPY(conditional_generate_construct,{s/~c~/c_/g}) // {copied} -//UNSUP ; +c_conditional_generate_construct: // IEEE: conditional_generate_construct (for checkers) + BISONPRE_COPY(conditional_generate_construct,{s/~c~/c_/g}) // {copied} + ; loop_generate_construct: // ==IEEE: loop_generate_construct yFOR '(' genvar_initialization ';' expr ';' genvar_iteration ')' ~c~generate_block_or_null @@ -2755,9 +2845,9 @@ loop_generate_construct: // ==IEEE: loop_generate_construct } ; -//UNSUPc_loop_generate_construct: // IEEE: loop_generate_construct (for checkers) -//UNSUP BISONPRE_COPY(loop_generate_construct,{s/~c~/c_/g}) // {copied} -//UNSUP ; +c_loop_generate_construct: // IEEE: loop_generate_construct (for checkers) + BISONPRE_COPY(loop_generate_construct,{s/~c~/c_/g}) // {copied} + ; genvar_initialization: // ==IEEE: genvar_initialization varRefBase '=' expr { $$ = new AstAssign{$2, $1, $3}; } @@ -2809,7 +2899,11 @@ genvar_iteration: // ==IEEE: genvar_iteration case_generate_itemListE: // IEEE: [{ case_generate_itemList }] /* empty */ { $$ = nullptr; } - | case_generate_itemList { $$ = $1; } + | ~c~case_generate_itemList { $$ = $1; } + ; + +c_case_generate_itemListE: // IEEE: { case_generate_item } (for checkers) + BISONPRE_COPY(case_generate_itemListE,{s/~c~/c_/g}) // {copied} ; case_generate_itemList: // IEEE: { case_generate_itemList } @@ -2817,19 +2911,19 @@ case_generate_itemList: // IEEE: { case_generate_itemList } | ~c~case_generate_itemList ~c~case_generate_item { $$ = $1; $1->addNext($2); } ; -//UNSUPc_case_generate_itemList: // IEEE: { case_generate_item } (for checkers) -//UNSUP BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied} -//UNSUP ; - -case_generate_item: // ==IEEE: case_generate_item - caseCondList colon generate_block_or_null { $$ = new AstCaseItem{$2, $1, $3}; } - | yDEFAULT colon generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $3}; } - | yDEFAULT generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $2}; } +c_case_generate_itemList: // IEEE: { case_generate_item } (for checkers) + BISONPRE_COPY(case_generate_itemList,{s/~c~/c_/g}) // {copied} ; -//UNSUPc_case_generate_item: // IEEE: case_generate_item (for checkers) -//UNSUP BISONPRE_COPY(case_generate_item,{s/~c~/c_/g}) // {copied} -//UNSUP ; +case_generate_item: // ==IEEE: case_generate_item + caseCondList colon ~c~generate_block_or_null { $$ = new AstCaseItem{$2, $1, $3}; } + | yDEFAULT colon ~c~generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $3}; } + | yDEFAULT ~c~generate_block_or_null { $$ = new AstCaseItem{$1, nullptr, $2}; } + ; + +c_case_generate_item: // IEEE: case_generate_item (for checkers) + BISONPRE_COPY(case_generate_item,{s/~c~/c_/g}) // {copied} + ; //************************************************ // Assignments and register declarations @@ -2847,7 +2941,8 @@ delay_or_event_controlE: // IEEE: delay_or_event_control plus empty /* empty */ { $$ = nullptr; } | delay_control { $$ = $1; } | event_control { $$ = $1; } -//UNSUP | yREPEAT '(' expr ')' event_control { } + | yREPEAT '(' expr ')' event_control + { $$ = $5; BBUNSUP($1, "Unsupported: repeat event control"); } ; delay_controlE: @@ -2863,7 +2958,7 @@ delay_control: //== IEEE: delay_control | '#' '(' minTypMax ',' minTypMax ')' { $$ = new AstDelay{$1, $3, false}; RISEFALLDLYUNSUP($3); DEL($5); } | '#' '(' minTypMax ',' minTypMax ',' minTypMax ')' - { $$ = new AstDelay{$1, $3, false}; RISEFALLDLYUNSUP($3); DEL($5); DEL($7); } + { $$ = new AstDelay{$1, $3, false}; RISEFALLDLYUNSUP($5); DEL($3); DEL($7); } ; delay_value: // ==IEEE:delay_value @@ -2905,7 +3000,20 @@ netId: | idSVKwd { $$ = $1; $$ = $1; } ; -sigAttrListE: +sigAttrScope: + yVL_PUBLIC_FLAT_RW_ON_SNS attr_event_control + { AstNode* sigAttrsp = new AstAttrOf{$1, VAttrType::VAR_PUBLIC_FLAT_RW}; + sigAttrsp->addNext(new AstAlwaysPublic{$1, $2, nullptr}); + GRAMMARP->setScopedSigAttr(sigAttrsp); + v3Global.dpi(true); } + | yVL_PUBLIC_ON { GRAMMARP->createScopedSigAttr(VAttrType::VAR_PUBLIC); } + | yVL_PUBLIC_FLAT_ON { GRAMMARP->createScopedSigAttr(VAttrType::VAR_PUBLIC_FLAT); } + | yVL_PUBLIC_FLAT_RD_ON { GRAMMARP->createScopedSigAttr(VAttrType::VAR_PUBLIC_FLAT_RD); } + | yVL_PUBLIC_FLAT_RW_ON { GRAMMARP->createScopedSigAttr(VAttrType::VAR_PUBLIC_FLAT_RW); } + | yVL_PUBLIC_OFF { GRAMMARP->setScopedSigAttr(nullptr); } + ; + +sigAttrListE: // Scoped Attributes are added to explicit attributes /* empty */ { $$ = nullptr; } | sigAttrList { $$ = $1; } ; @@ -2942,11 +3050,6 @@ rangeList: // IEEE: {packed_dimension} | rangeList anyrange { $$ = $1->addNext($2); } ; -//UNSUPbit_selectE: // IEEE: constant_bit_select (IEEE included empty) -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | '[' constExpr ']' { $$ = $1; $$ = "[" + $2 + "]"; } -//UNSUP ; - // IEEE: select // Merged into more general idArray @@ -2977,14 +3080,7 @@ param_assignment: // ==IEEE: param_assignment // // IEEE: constant_param_expression // // constant_param_expression: '$' is in expr id/*new-parameter*/ variable_dimensionListE sigAttrListE exprOrDataTypeEqE - { // To handle #(type A=int, B=A) and properly imply B - // as a type (for parsing) we need to detect "A" is a type - if (AstNodeDType* const refp = VN_CAST($4, NodeDType)) { - if (VSymEnt* const foundp = SYMP->symCurrentp()->findIdFallback(refp->name())) { - UINFO(9, "declaring type via param assignment" << foundp->nodep() << endl); - VARDTYPE(new AstParseTypeDType{$1}); - SYMP->reinsert(foundp->nodep()->cloneTree(false), nullptr, *$1); }} - $$ = VARDONEA($1, *$1, $2, $3); + { $$ = VARDONEA($1, *$1, $2, $3); if ($4) $$->valuep($4); } ; @@ -3067,11 +3163,11 @@ instnameList: ; instnameParen: - id instRangeListE '(' cellpinList ')' + id instRangeListE '(' cellpinListE ')' { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, $4, $2); } | id instRangeListE { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, nullptr, $2); } - //UNSUP instRangeListE '(' cellpinList ')' { UNSUP } // UDP + //UNSUP instRangeListE '(' cellpinListE ')' { UNSUP } // UDP // // Adding above and switching to the Verilog-Perl syntax // // causes a shift conflict due to use of idClassSel inside exprScope. // // It also breaks allowing "id foo;" instantiation syntax. @@ -3094,40 +3190,44 @@ instRange: { $$ = new AstRange{$1, $2, $4}; } ; -cellparamList: - { GRAMMARP->pinPush(); } cellparamItList { $$ = $2; GRAMMARP->pinPop(CRELINE()); } +cellparamListE: + { GRAMMARP->pinPush(); } cellparamItListE { $$ = $2; GRAMMARP->pinPop(CRELINE()); } ; -cellpinList: - {VARRESET_LIST(UNKNOWN);} cellpinItList { $$ = $2; VARRESET_NONLIST(UNKNOWN); } +cellpinListE: + { VARRESET_LIST(UNKNOWN); } cellpinItListE { $$ = $2; VARRESET_NONLIST(UNKNOWN); } ; -cellparamItList: // IEEE: list_of_parameter_assignmente +cellparamItListE: // IEEE: list_of_parameter_assignmente cellparamItemE { $$ = $1; } - | cellparamItList ',' cellparamItemE { $$ = addNextNull($1, $3); } + | cellparamItListE ',' cellparamItemE { $$ = addNextNull($1, $3); } ; -cellpinItList: // IEEE: list_of_port_connections +cellpinItListE: // IEEE: list_of_port_connections cellpinItemE { $$ = $1; } - | cellpinItList ',' cellpinItemE { $$ = addNextNull($1, $3); } + | cellpinItListE ',' cellpinItemE { $$ = addNextNull($1, $3); } ; cellparamItemE: // IEEE: named_parameter_assignment + empty // // Note empty can match either () or (,); V3LinkCells cleans up () /* empty: ',,' is legal */ { $$ = new AstPin{CRELINE(), PINNUMINC(), "", nullptr}; } | yP_DOTSTAR { $$ = new AstPin{$1, PINNUMINC(), ".*", nullptr}; } - | '.' idAny '(' ')' { $$ = new AstPin{$2, PINNUMINC(), *$2, nullptr}; } + | '.' idAny '(' ')' + { $$ = new AstPin{$2, PINNUMINC(), *$2, nullptr}; + $$->svDotName(true); } | '.' idSVKwd { $$ = new AstPin{$2, PINNUMINC(), *$2, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}}; - $$->svImplicit(true); } + $$->svDotName(true); $$->svImplicit(true); } | '.' idAny { $$ = new AstPin{$2, PINNUMINC(), *$2, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}}; - $$->svImplicit(true); } + $$->svDotName(true); $$->svImplicit(true); } // // mintypmax is expanded here, as it might be a UDP or gate primitive // // data_type for 'parameter type' hookups - | '.' idAny '(' exprOrDataType ')' { $$ = new AstPin{$2, PINNUMINC(), *$2, $4}; } + | '.' idAny '(' exprOrDataType ')' + { $$ = new AstPin{$2, PINNUMINC(), *$2, $4}; + $$->svDotName(true); } //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ')' { } //UNSUP '.' idAny '(' exprOrDataType/*expr*/ ':' expr ':' expr ')' { } // // data_type for 'parameter type' hookups @@ -3140,18 +3240,22 @@ cellpinItemE: // IEEE: named_port_connection + empty // // Note empty can match either () or (,); V3LinkCells cleans up () /* empty: ',,' is legal */ { $$ = new AstPin{CRELINE(), PINNUMINC(), "", nullptr}; } | yP_DOTSTAR { $$ = new AstPin{$1, PINNUMINC(), ".*", nullptr}; } - | '.' idAny '(' ')' { $$ = new AstPin{$2, PINNUMINC(), *$2, nullptr}; } + | '.' idAny '(' ')' + { $$ = new AstPin{$2, PINNUMINC(), *$2, nullptr}; + $$->svDotName(true); } | '.' idSVKwd { $$ = new AstPin{$2, PINNUMINC(), *$2, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}}; - $$->svImplicit(true);} + $$->svDotName(true); $$->svImplicit(true); } | '.' idAny { $$ = new AstPin{$2, PINNUMINC(), *$2, new AstParseRef{$2, VParseRefExp::PX_TEXT, *$2, nullptr, nullptr}}; - $$->svImplicit(true);} + $$->svDotName(true); $$->svImplicit(true); } // // mintypmax is expanded here, as it might be a UDP or gate primitive //UNSUP pev_expr below - | '.' idAny '(' expr ')' { $$ = new AstPin{$2, PINNUMINC(), *$2, $4}; } + | '.' idAny '(' expr ')' + { $$ = new AstPin{$2, PINNUMINC(), *$2, $4}; + $$->svDotName(true); } //UNSUP '.' idAny '(' pev_expr ':' expr ')' { } //UNSUP '.' idAny '(' pev_expr ':' expr ':' expr ')' { } // @@ -3491,7 +3595,7 @@ statement_item: // IEEE: statement_item // // IEEE: procedural_assertion_statement | procedural_assertion_statement { $$ = $1; } // - //UNSUP randsequence_statement { $$ = $1; } + | randsequence_statement { $$ = $1; } // // // IEEE: randcase_statement | yRANDCASE rand_case_itemList yENDCASE { $$ = new AstRandCase{$1, $2}; } @@ -3622,11 +3726,11 @@ unique_priorityE: // IEEE: unique_priority + empty ; caseStart: // IEEE: part of case_statement - yCASE '(' expr ')' + yCASE '(' exprTypeCompare ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase{$1, VCaseType::CT_CASE, $3, nullptr}; } - | yCASEX '(' expr ')' + | yCASEX '(' exprTypeCompare ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase{$1, VCaseType::CT_CASEX, $3, nullptr}; } - | yCASEZ '(' expr ')' + | yCASEZ '(' exprTypeCompare ')' { $$ = GRAMMARP->m_caseAttrp = new AstCase{$1, VCaseType::CT_CASEZ, $3, nullptr}; } ; @@ -3695,8 +3799,8 @@ value_range: // ==IEEE: value_range //UNSUP ; caseCondList: // IEEE: part of case_item - expr { $$ = $1; } - | caseCondList ',' expr { $$ = $1->addNext($3); } + exprTypeCompare { $$ = $1; } + | caseCondList ',' exprTypeCompare { $$ = $1->addNext($3); } ; patternNoExpr: // IEEE: pattern **Excluding Expr* @@ -3788,12 +3892,16 @@ for_initializationItem: // IEEE: variable_assignment + for_varia // // IEEE: for_variable_declaration data_type idAny/*new*/ '=' expr { VARRESET_NONLIST(VAR); VARDTYPE($1); - $$ = VARDONEA($2, *$2, nullptr, nullptr); + AstVar* const varp = VARDONEA($2, *$2, nullptr, nullptr); + varp->lifetime(VLifetime::AUTOMATIC); + $$ = varp; $$->addNext(new AstAssign{$3, new AstVarRef{$2, *$2, VAccess::WRITE}, $4}); } // // IEEE-2012: | yVAR data_type idAny/*new*/ '=' expr { VARRESET_NONLIST(VAR); VARDTYPE($2); - $$ = VARDONEA($3, *$3, nullptr, nullptr); + AstVar* const varp = VARDONEA($3, *$3, nullptr, nullptr); + varp->lifetime(VLifetime::AUTOMATIC); + $$ = varp; $$->addNext(new AstAssign{$4, new AstVarRef{$3, *$3, VAccess::WRITE}, $5}); } // // IEEE: variable_assignment // // UNSUP variable_lvalue below @@ -3974,10 +4082,12 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_FMONITORB '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'b'}; } | yD_FMONITORH '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'h'}; } | yD_FMONITORO '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_MONITOR, $3, $5, 'o'}; } + | yD_FSTROBE '(' expr ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, $3, nullptr}; } | yD_FSTROBE '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, $3, $5}; } | yD_FSTROBEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, $3, $5, 'b'}; } | yD_FSTROBEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, $3, $5, 'h'}; } | yD_FSTROBEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_STROBE, $3, $5, 'o'}; } + | yD_FWRITE '(' expr ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, $3, nullptr}; } | yD_FWRITE '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, $3, $5}; } | yD_FWRITEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, $3, $5, 'b'}; } | yD_FWRITEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay{$1, VDisplayType::DT_WRITE, $3, $5, 'h'}; } @@ -4062,8 +4172,11 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task | yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD{$1, $3}; } | yD_BITSTOSHORTREAL '(' expr ')' { $$ = new AstBitsToRealD{$1, $3}; UNSUPREAL($1); } | yD_CEIL '(' expr ')' { $$ = new AstCeilD{$1, $3}; } - | yD_CHANGED '(' expr ')' { $$ = new AstLogNot{$1, new AstStable{$1, $3}}; } - | yD_CHANGED '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $changed and clock arguments"); } + | yD_CHANGED '(' expr ')' { $$ = new AstLogNot{$1, new AstStable{$1, $3, nullptr}}; } + | yD_CHANGED '(' expr ',' expr ')' + { $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createClockSenTree($1, $5)}}; } + | yD_CHANGED_GCLK '(' expr ')' + { $$ = new AstLogNot{$1, new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}}; } | yD_CLOG2 '(' expr ')' { $$ = new AstCLog2{$1, $3}; } | yD_COS '(' expr ')' { $$ = new AstCosD{$1, $3}; } | yD_COSH '(' expr ')' { $$ = new AstCoshD{$1, $3}; } @@ -4083,20 +4196,22 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task | yD_DIST_T '(' expr ',' expr ')' { $$ = new AstDistT{$1, $3, $5}; } | yD_DIST_UNIFORM '(' expr ',' expr ',' expr ')' { $$ = new AstDistUniform{$1, $3, $5, $7}; } | yD_EXP '(' expr ')' { $$ = new AstExpD{$1, $3}; } - | yD_FELL '(' expr ')' { $$ = new AstFell{$1, $3}; } - | yD_FELL '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $fell and clock arguments"); } + | yD_FELL '(' expr ')' { $$ = new AstFell{$1, $3, nullptr}; } + | yD_FELL '(' expr ',' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; } + | yD_FELL_GCLK '(' expr ')' { $$ = new AstFell{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; } | yD_FEOF '(' expr ')' { $$ = new AstFEof{$1, $3}; } - | yD_FERROR '(' idClassSel ',' idClassSel ')' { $$ = new AstFError{$1, $3, $5}; } + | yD_FERROR '(' expr ',' idClassSel ')' { $$ = new AstFError{$1, $3, $5}; } | yD_FGETC '(' expr ')' { $$ = new AstFGetC{$1, $3}; } - | yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS{$1, $3, $5}; } - | yD_FREAD '(' idClassSel ',' expr ')' { $$ = new AstFRead{$1, $3, $5, nullptr, nullptr}; } - | yD_FREAD '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, $7, nullptr}; } - | yD_FREAD '(' idClassSel ',' expr ',' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, $7, $9}; } - | yD_FREWIND '(' idClassSel ')' { $$ = new AstFRewind{$1, $3}; } + | yD_FGETS '(' expr ',' expr ')' { $$ = new AstFGetS{$1, $3, $5}; } + | yD_FREAD '(' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, nullptr, nullptr}; } + | yD_FREAD '(' expr ',' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, $7, nullptr}; } + | yD_FREAD '(' expr ',' expr ',' expr ',' expr ')' { $$ = new AstFRead{$1, $3, $5, $7, $9}; } + | yD_FREWIND '(' expr ')' { $$ = new AstFRewind{$1, $3}; } | yD_FLOOR '(' expr ')' { $$ = new AstFloorD{$1, $3}; } | yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF{$1, *$5, $3, $6}; } - | yD_FSEEK '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFSeek{$1, $3, $5, $7}; } - | yD_FTELL '(' idClassSel ')' { $$ = new AstFTell{$1, $3}; } + | yD_FSEEK '(' expr ',' expr ',' expr ')' { $$ = new AstFSeek{$1, $3, $5, $7}; } + | yD_FTELL '(' expr ')' { $$ = new AstFTell{$1, $3}; } + | yD_GLOBAL_CLOCK parenE { $$ = GRAMMARP->createGlobalClockParseRef($1); } | yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, nullptr}; } | yD_HIGH '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, $5}; } | yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD{$1, $3, $5}; } @@ -4124,11 +4239,12 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task | yD_RANDOM parenE { $$ = new AstRand{$1, nullptr, false}; } | yD_REALTIME parenE { $$ = new AstTimeD{$1, VTimescale{VTimescale::NONE}}; } | yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits{$1, $3}; } - | yD_REWIND '(' idClassSel ')' { $$ = new AstFSeek{$1, $3, new AstConst{$1, 0}, new AstConst{$1, 0}}; } + | yD_REWIND '(' expr ')' { $$ = new AstFSeek{$1, $3, new AstConst{$1, 0}, new AstConst{$1, 0}}; } | yD_RIGHT '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, nullptr}; } | yD_RIGHT '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_RIGHT, $3, $5}; } - | yD_ROSE '(' expr ')' { $$ = new AstRose{$1, $3}; } - | yD_ROSE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $rose and clock arguments"); } + | yD_ROSE '(' expr ')' { $$ = new AstRose{$1, $3, nullptr}; } + | yD_ROSE '(' expr ',' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; } + | yD_ROSE_GCLK '(' expr ')' { $$ = new AstRose{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; } | yD_RTOI '(' expr ')' { $$ = new AstRToIS{$1, $3}; } | yD_SAMPLED '(' expr ')' { $$ = new AstSampled{$1, $3}; } | yD_SFORMATF '(' exprDispList ')' { $$ = new AstSFormatF{$1, AstSFormatF::NoFormat{}, $3, 'd', false}; } @@ -4142,8 +4258,9 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task | yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF{$1, *$5, $3, $6}; } | yD_STIME parenE { $$ = new AstSel{$1, new AstTime{$1, VTimescale{VTimescale::NONE}}, 0, 32}; } - | yD_STABLE '(' expr ')' { $$ = new AstStable{$1, $3}; } - | yD_STABLE '(' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $stable and clock arguments"); } + | yD_STABLE '(' expr ')' { $$ = new AstStable{$1, $3, nullptr}; } + | yD_STABLE '(' expr ',' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createClockSenTree($1, $5)}; } + | yD_STABLE_GCLK '(' expr ')' { $$ = new AstStable{$1, $3, GRAMMARP->createGlobalClockSenTree($1)}; } | yD_TAN '(' expr ')' { $$ = new AstTanD{$1, $3}; } | yD_TANH '(' expr ')' { $$ = new AstTanhD{$1, $3}; } | yD_TESTPLUSARGS '(' expr ')' { $$ = new AstTestPlusArgs{$1, $3}; } @@ -4627,6 +4744,11 @@ expr: // IEEE: part of expression/constant_expression/ | ~l~expr yP_SSRIGHT ~r~expr { $$ = new AstShiftRS{$2, $1, $3}; } | ~l~expr yP_LTMINUSGT ~r~expr { $$ = new AstLogEq{$2, $1, $3}; } // + // // IEEE: expression binary_operator expression (type compare see IEEE footnote) + | type_referenceEq yP_CASEEQUAL type_referenceBoth { $$ = new AstEqT{$2, $1, $3}; } + | type_referenceEq yP_CASENOTEQUAL type_referenceBoth { $$ = new AstNeqT{$2, $1, $3}; } + | type_referenceEq yP_EQUAL type_referenceBoth { $$ = new AstEqT{$2, $1, $3}; } + | type_referenceEq yP_NOTEQUAL type_referenceBoth { $$ = new AstNeqT{$2, $1, $3}; } // // IEEE: expr yP_MINUSGT expr (1800-2009) // // Conflicts with constraint_expression:"expr yP_MINUSGT constraint_set" // // To duplicating expr for constraints, just allow the more general form @@ -4681,7 +4803,7 @@ expr: // IEEE: part of expression/constant_expression/ // // IEEE: '(' mintypmax_expression ')' | ~noPar__IGNORE~'(' expr ')' { $$ = $2; } | ~noPar__IGNORE~'(' expr ':' expr ':' expr ')' - { $$ = $2; BBUNSUP($1, "Unsupported: min typ max expressions"); } + { $$ = $4; MINTYPMAXDLYUNSUP($4); DEL($2); DEL($6); } // // PSL rule | '_' '(' expr ')' { $$ = $3; } // Arbitrary Verilog inside PSL // @@ -4689,7 +4811,7 @@ expr: // IEEE: part of expression/constant_expression/ // // expanded from casting_type | simple_type yP_TICK '(' expr ')' { $$ = new AstCast{$1->fileline(), $4, VFlagChildDType{}, $1}; } - | yTYPE '(' exprOrDataType ')' yP_TICK '(' expr ')' + | yTYPE__ETC '(' exprOrDataType ')' yP_TICK '(' expr ')' { $$ = new AstCast{$1, $7, VFlagChildDType{}, new AstRefDType{$1, AstRefDType::FlagTypeOfExpr{}, $3}}; } | ySIGNED yP_TICK '(' expr ')' { $$ = new AstSigned{$1, $4}; } @@ -4864,6 +4986,11 @@ exprStrText: | strAsText { $$ = $1; } ; +exprTypeCompare: + expr { $$ = $1; } + | type_referenceBoth { $$ = $1; } + ; + cStrList: exprStrText { $$ = $1; } | exprStrText ',' cStrList { $$ = $1->addNext($3); } @@ -4978,18 +5105,26 @@ stream_concatenation: // ==IEEE: stream_concatenation stream_expression: // ==IEEE: stream_expression // // IEEE: array_range_expression expanded below expr { $$ = $1; } - //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr ':' expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { UNSUP } + | expr yWITH__BRA '[' expr ']' + { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } + | expr yWITH__BRA '[' expr ':' expr ']' + { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } + | expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' + { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } + | expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' + { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } ; stream_expressionOrDataType: // IEEE: from streaming_concatenation exprOrDataType { $$ = $1; } - //UNSUP expr yWITH__BRA '[' expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr ':' expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' { UNSUP } - //UNSUP expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' { UNSUP } + | expr yWITH__BRA '[' expr ']' + { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } + | expr yWITH__BRA '[' expr ':' expr ']' + { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } + | expr yWITH__BRA '[' expr yP_PLUSCOLON expr ']' + { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } + | expr yWITH__BRA '[' expr yP_MINUSCOLON expr ']' + { $$ = $1; BBUNSUP($2, "Unsupported: with[] stream expression"); } ; //************************************************ @@ -5091,10 +5226,28 @@ gateRangeE: ; gateBuf: - gateFront variable_lvalue ',' gatePinExpr ')' - { $$ = new AstAssignW{$1, $2, $4}; DEL($1); } - // UNSUP // IEEE: Multiple output variable_lvalues - // UNSUP // Causes conflict - need to take in variable_lvalue or a gatePinExpr + gateFront variable_lvalue ',' exprList ')' + { AstNodeExpr* inp = $4; + while (inp->nextp()) inp = VN_AS(inp->nextp(), NodeExpr); + $$ = new AstAssignW{$1, $2, GRAMMARP->createGatePin(inp->cloneTree(false))}; + for (AstNodeExpr* outp = $4; outp->nextp(); outp = VN_CAST(outp->nextp(), NodeExpr)) { + $$->addNext(new AstAssignW{$1, outp->cloneTree(false), + GRAMMARP->createGatePin(inp->cloneTree(false))}); + } + DEL($1); DEL($4); } + ; +gateNot: + gateFront variable_lvalue ',' exprList ')' + { AstNodeExpr* inp = $4; + while (inp->nextp()) inp = VN_AS(inp->nextp(), NodeExpr); + $$ = new AstAssignW{$1, $2, new AstNot{$1, + GRAMMARP->createGatePin(inp->cloneTree(false))}}; + for (AstNodeExpr* outp = $4; outp->nextp(); outp = VN_CAST(outp->nextp(), NodeExpr)) { + $$->addNext(new AstAssignW{$1, outp->cloneTree(false), + new AstNot{$1, + GRAMMARP->createGatePin(inp->cloneTree(false))}}); + } + DEL($1); DEL($4); } ; gateBufif0: gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' @@ -5104,12 +5257,6 @@ gateBufif1: gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' { $$ = new AstAssignW{$1, $2, new AstBufIf1{$1, $6, $4}}; DEL($1); } ; -gateNot: - gateFront variable_lvalue ',' gatePinExpr ')' - { $$ = new AstAssignW{$1, $2, new AstNot{$1, $4}}; DEL($1); } - // UNSUP // IEEE: Multiple output variable_lvalues - // UNSUP // Causes conflict - need to take in variable_lvalue or a gatePinExpr - ; gateNotif0: gateFront variable_lvalue ',' gatePinExpr ',' gatePinExpr ')' { $$ = new AstAssignW{$1, $2, new AstBufIf1{$1, new AstNot{$1, $6}, @@ -5437,17 +5584,15 @@ endLabelE: clocking_declaration: // IEEE: clocking_declaration yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE - { $$ = new AstClocking{$2, *$2, $3, $5, false}; } + { $$ = new AstClocking{$2, *$2, $3, $5, false, false}; } | yDEFAULT yCLOCKING clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE - { $$ = new AstClocking{$2, "", $3, $5, true}; } + { $$ = new AstClocking{$2, "", $3, $5, true, false}; } | yDEFAULT yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE - { $$ = new AstClocking{$3, *$3, $4, $6, true}; } + { $$ = new AstClocking{$3, *$3, $4, $6, true, false}; } | yGLOBAL__CLOCKING yCLOCKING clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE - { $$ = nullptr; - BBUNSUP($2, "Unsupported: global clocking"); } + { $$ = new AstClocking{$2, "", $3, $5, false, true}; } | yGLOBAL__CLOCKING yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE - { $$ = nullptr; - BBUNSUP($3, "Unsupported: global clocking"); } + { $$ = new AstClocking{$3, *$3, $4, $6, false, true}; } ; clocking_event: // IEEE: clocking_event @@ -5678,19 +5823,19 @@ property_port_item: // IEEE: property_port_item/sequence_port_item ; property_port_itemFront: // IEEE: part of property_port_item/sequence_port_item - property_port_itemDirE property_formal_typeNoDt { VARDTYPE($2); } -//UNSUP // // data_type_or_implicit + property_port_itemDirE property_formal_typeNoDt { VARDTYPE($2); } + // // data_type_or_implicit | property_port_itemDirE data_type { VARDTYPE($2); GRAMMARP->m_typedPropertyPort = true; } -//UNSUP | property_port_itemDirE yVAR data_type { VARDTYPE($3); } -//UNSUP | property_port_itemDirE yVAR implicit_typeE { VARDTYPE($3); } -//UNSUP | property_port_itemDirE signingE rangeList { VARDTYPE(SPACED($2, $3)); } + | property_port_itemDirE yVAR data_type + { VARDTYPE($3); GRAMMARP->m_typedPropertyPort = true; } + | property_port_itemDirE yVAR implicit_typeE { VARDTYPE($3); } | property_port_itemDirE implicit_typeE { VARDTYPE($2); } ; property_port_itemAssignment: // IEEE: part of property_port_item/sequence_port_item/checker_port_direction id variable_dimensionListE { $$ = VARDONEA($1, *$1, $2, nullptr); } -//UNSUP | portSig variable_dimensionListE '=' property_actual_arg +//UNSUP | id variable_dimensionListE '=' property_actual_arg //UNSUP { VARDONE($1, $1, $2, $4); PINNUMINC(); } ; @@ -5853,7 +5998,6 @@ pexpr: // IEEE: property_expr (The name pexpr is important as regex complex_pexpr: // IEEE: part of property_expr, see comments there expr yP_ORMINUSGT pexpr { $$ = new AstLogOr{$2, new AstLogNot{$2, $1}, $3}; } | expr yP_OREQGT pexpr { $$ = new AstImplication{$2, $1, $3}; } - | yNOT pexpr %prec prNEGATION { $$ = new AstLogNot{$1, $2}; } | '(' complex_pexpr ')' { $$ = $2; } //UNSUP remove above, use below: // @@ -5863,7 +6007,7 @@ complex_pexpr: // IEEE: part of property_expr, see comments there // // IEEE: '(' pexpr ')' // // Expanded below // - //UNSUP yNOT pexpr %prec prNEGATION { } + | yNOT pexpr %prec prNEGATION { $$ = new AstLogNot{$1, $2}; } //UNSUP ySTRONG '(' sexpr ')' { } //UNSUP yWEAK '(' sexpr ')' { } // // IEEE: pexpr yOR pexpr @@ -6167,7 +6311,8 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //UNSUPlist_of_cross_items: // ==IEEE: list_of_cross_items //UNSUP cross_item ',' cross_item { $$ = addNextNull($1, $3); } -//UNSUP | cross_item ',' cross_item ',' cross_itemList { } +//UNSUP | cross_item ',' cross_item ',' cross_itemList +//UNSUP { $$ = addNextNull(addNextNull($1, $3), $5); } //UNSUP ; //UNSUPcross_itemList: // IEEE: part of list_of_cross_items @@ -6261,173 +6406,207 @@ complex_pexpr: // IEEE: part of property_expr, see comments there //********************************************************************** // Randsequence -//UNSUPrandsequence_statement: // ==IEEE: randsequence_statement -//UNSUP yRANDSEQUENCE '(' ')' productionList yENDSEQUENCE { } -//UNSUP | yRANDSEQUENCE '(' id/*production_identifier*/ ')' productionList yENDSEQUENCE { } -//UNSUP ; +randsequence_statement: // ==IEEE: randsequence_statement + yRANDSEQUENCE '(' ')' productionList yENDSEQUENCE + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence"); } + | yRANDSEQUENCE '(' id/*production_identifier*/ ')' productionList yENDSEQUENCE + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence"); } + ; -//UNSUPproductionList: // IEEE: production+ -//UNSUP production { $$ = $1; } -//UNSUP | productionList production { $$ = addNextNull($1, $2); } -//UNSUP ; +productionList: // IEEE: production+ + production { $$ = $1; } + | productionList production { $$ = addNextNull($1, $2); } + ; -//UNSUPproduction: // ==IEEE: production -//UNSUP productionFront ':' rs_ruleList ';' { } -//UNSUP ; +production: // ==IEEE: production + productionFront ':' rs_ruleList ';' + { // TODO makes a function, probably want a new Ast type instead + SYMP->popScope($$); + $$ = nullptr; BBUNSUP($2, "Unsupported: randsequence production"); } + ; -//UNSUPproductionFront: // IEEE: part of production -//UNSUP function_data_type id/*production_identifier*/ { } -//UNSUP | /**/ id/*production_identifier*/ { $$ = $1; } -//UNSUP | function_data_type id/*production_identifier*/ '(' tf_port_listE ')' { } -//UNSUP | /**/ id/*production_identifier*/ '(' tf_port_listE ')' { } -//UNSUP ; +productionFront: // IEEE: part of production + funcId/*production_identifier*/ { $$ = $1; } + | funcId '(' tf_port_listE ')' { $$ = $1; $$->addStmtsp($3); } + ; -//UNSUPrs_ruleList: // IEEE: rs_rule+ part of production -//UNSUP rs_rule { $$ = $1; } -//UNSUP | rs_ruleList '|' rs_rule { $$ = addNextNull($1, $3); } -//UNSUP ; +rs_ruleList: // IEEE: rs_rule+ part of production + rs_rule { $$ = $1; } + | rs_ruleList '|' rs_rule { $$ = addNextNull($1, $3); } + ; -//UNSUPrs_rule: // ==IEEE: rs_rule -//UNSUP rs_production_list { $$ = $1; } -//UNSUP | rs_production_list yP_COLONEQ weight_specification { } -//UNSUP | rs_production_list yP_COLONEQ weight_specification rs_code_block { } -//UNSUP ; +rs_rule: // ==IEEE: rs_rule + rs_production_list { $$ = $1; } + | rs_production_list yP_COLONEQ weight_specification + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence rule"); } + | rs_production_list yP_COLONEQ weight_specification rs_code_block + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence rule"); } + ; -//UNSUPrs_production_list: // ==IEEE: rs_production_list -//UNSUP rs_prodList { $$ = $1; } -//UNSUP | yRAND yJOIN /**/ production_item production_itemList { } -//UNSUP | yRAND yJOIN '(' expr ')' production_item production_itemList { } -//UNSUP ; +rs_production_list: // ==IEEE: rs_production_list + rs_prodList { $$ = $1; } + | yRAND yJOIN /**/ production_item production_itemList + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production list"); } + | yRAND yJOIN '(' expr ')' production_item production_itemList + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production list"); } + ; -//UNSUPweight_specification: // ==IEEE: weight_specification -//UNSUP yaINTNUM { $$ = $1; } -//UNSUP | idClassSel/*ps_identifier*/ { $$ = $1; } -//UNSUP | '(' expr ')' { $$ = $2; } -//UNSUP ; +weight_specification: // ==IEEE: weight_specification + intnumAsConst { $$ = $1; } + | idClassSel/*ps_identifier*/ { $$ = $1; } + | '(' expr ')' { $$ = $2; } + ; -//UNSUPrs_code_block: // ==IEEE: rs_code_block -//UNSUP '{' '}' { $$ = nullptr; } -//UNSUP | '{' rs_code_blockItemList '}' { $$ = $2; } -//UNSUP ; +rs_code_block: // ==IEEE: rs_code_block + '{' '}' { $$ = nullptr; } + | '{' rs_code_blockItemList '}' { $$ = $2; } + ; -//UNSUPrs_code_blockItemList: // IEEE: part of rs_code_block -//UNSUP rs_code_blockItem { $$ = $1; } -//UNSUP | rs_code_blockItemList rs_code_blockItem { $$ = addNextNull($1, $2); } -//UNSUP ; +rs_code_blockItemList: // IEEE: part of rs_code_block + rs_code_blockItem { $$ = $1; } + | rs_code_blockItemList rs_code_blockItem { $$ = addNextNull($1, $2); } + ; -//UNSUPrs_code_blockItem: // IEEE: part of rs_code_block -//UNSUP data_declaration { $$ = $1; } -//UNSUP | stmt { $$ = $1; } -//UNSUP ; +rs_code_blockItem: // IEEE: part of rs_code_block + data_declaration { $$ = $1; } + | stmt { $$ = $1; } + ; -//UNSUPrs_prodList: // IEEE: rs_prod+ -//UNSUP rs_prod { $$ = $1; } -//UNSUP | rs_prodList rs_prod { $$ = addNextNull($1, $2); } -//UNSUP ; +rs_prodList: // IEEE: rs_prod+ + rs_prod { $$ = $1; } + | rs_prodList rs_prod { $$ = addNextNull($1, $2); } + ; -//UNSUPrs_prod: // ==IEEE: rs_prod -//UNSUP production_item { $$ = $1; } -//UNSUP | rs_code_block { $$ = $1; } -//UNSUP // // IEEE: rs_if_else -//UNSUP | yIF '(' expr ')' production_item %prec prLOWER_THAN_ELSE { } -//UNSUP | yIF '(' expr ')' production_item yELSE production_item { } -//UNSUP // // IEEE: rs_repeat -//UNSUP | yREPEAT '(' expr ')' production_item { } -//UNSUP // // IEEE: rs_case -//UNSUP | yCASE '(' expr ')' rs_case_itemList yENDCASE { } -//UNSUP ; +rs_prod: // ==IEEE: rs_prod + production_item { $$ = $1; } + | rs_code_block { $$ = $1; } + // // IEEE: rs_if_else + | yIF '(' expr ')' production_item %prec prLOWER_THAN_ELSE + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence if"); } + | yIF '(' expr ')' production_item yELSE production_item + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence if"); } + // // IEEE: rs_repeat + | yREPEAT '(' expr ')' production_item + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence repeat"); } + // // IEEE: rs_case + | yCASE '(' expr ')' rs_case_itemList yENDCASE + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case"); } + ; -//UNSUPproduction_itemList: // IEEE: production_item+ -//UNSUP production_item { $$ = $1; } -//UNSUP | production_itemList production_item { $$ = addNextNull($1, $2); } -//UNSUP ; +production_itemList: // IEEE: production_item+ + production_item { $$ = $1; } + | production_itemList production_item { $$ = addNextNull($1, $2); } + ; -//UNSUPproduction_item: // ==IEEE: production_item -//UNSUP id/*production_identifier*/ { $$ = $1; } -//UNSUP | id/*production_identifier*/ '(' list_of_argumentsE ')' { } -//UNSUP ; +production_item: // ==IEEE: production_item + id/*production_identifier*/ + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production id"); } + | id/*production_identifier*/ '(' list_of_argumentsE ')' + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence production id"); } + ; -//UNSUPrs_case_itemList: // IEEE: rs_case_item+ -//UNSUP rs_case_item { $$ = $1; } -//UNSUP | rs_case_itemList rs_case_item { $$ = addNextNull($1, $2); } -//UNSUP ; +rs_case_itemList: // IEEE: rs_case_item+ + rs_case_item { $$ = $1; } + | rs_case_itemList rs_case_item { $$ = addNextNull($1, $2); } + ; -//UNSUPrs_case_item: // ==IEEE: rs_case_item -//UNSUP caseCondList ':' production_item ';' { } -//UNSUP | yDEFAULT production_item ';' { } -//UNSUP | yDEFAULT ':' production_item ';' { } -//UNSUP ; +rs_case_item: // ==IEEE: rs_case_item + caseCondList ':' production_item ';' + { $$ = nullptr; BBUNSUP($2, "Unsupported: randsequence case item"); } + | yDEFAULT production_item ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case item"); } + | yDEFAULT ':' production_item ';' + { $$ = nullptr; BBUNSUP($1, "Unsupported: randsequence case item"); } + ; //********************************************************************** // Checker -//UNSUPchecker_declaration: // ==IEEE: part of checker_declaration -//UNSUP checkerFront checker_port_listE ';' -//UNSUP checker_or_generate_itemListE yENDCHECKER endLabelE -//UNSUP { SYMP->popScope($$); } -//UNSUP ; +checker_declaration: // ==IEEE: part of checker_declaration + checkerFront checker_port_listE ';' + checker_or_generate_itemListE yENDCHECKER endLabelE + { $$ = $1; + $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); + if ($2) $1->addStmtsp($2); + if ($4) $1->addStmtsp($4); + GRAMMARP->m_modp = nullptr; + SYMP->popScope($1); + GRAMMARP->endLabel($6, $1, $6); } + ; -//UNSUPcheckerFront: // IEEE: part of checker_declaration -//UNSUP yCHECKER idAny/*checker_identifier*/ -//UNSUP { SYMP->pushNew($$); } -//UNSUP ; +checkerFront: // IEEE: part of checker_declaration + yCHECKER idAny/*checker_identifier*/ + { BBUNSUP($1, "Unsupported: checker"); + // TODO should be AstChecker not AstModule + $$ = new AstModule{$2, *$2}; + $$->modTrace(GRAMMARP->allTracingOn($$->fileline())); + $$->timeunit(PARSEP->timeLastUnit()); + $$->unconnectedDrive(PARSEP->unconnectedDrive()); + SYMP->pushNew($$); + GRAMMARP->m_modp = $$; } + ; -//UNSUPchecker_port_listE: // IEEE: [ ( [ checker_port_list ] ) ] -//UNSUP // // checker_port_item is basically the same as property_port_item, minus yLOCAL:: -//UNSUP // // Want to bet 1800-2012 adds local to checkers? -//UNSUP property_port_listE { $$ = $1; } -//UNSUP ; +checker_port_listE: // IEEE: [ ( [ checker_port_list ] ) ] + // // checker_port_item is basically the same as property_port_item, minus yLOCAL:: + // // Want to bet 1800-2012 adds local to checkers? + property_port_listE { $$ = $1; } + ; -//UNSUPchecker_or_generate_itemListE: // IEEE: [{ checker_or_generate_itemList }] -//UNSUP /* empty */ { $$ = nullptr; } -//UNSUP | checker_or_generate_itemList { $$ = $1; } -//UNSUP ; +checker_or_generate_itemListE: // IEEE: [{ checker_or_generate_itemList }] + /* empty */ { $$ = nullptr; } + | checker_or_generate_itemList { $$ = $1; } + ; -//UNSUPchecker_or_generate_itemList: // IEEE: { checker_or_generate_itemList } -//UNSUP checker_or_generate_item { $$ = $1; } -//UNSUP | checker_or_generate_itemList checker_or_generate_item { $$ = addNextNull($1, $2); } -//UNSUP ; +checker_or_generate_itemList: // IEEE: { checker_or_generate_itemList } + checker_or_generate_item { $$ = $1; } + | checker_or_generate_itemList checker_or_generate_item { $$ = addNextNull($1, $2); } + ; -//UNSUPchecker_or_generate_item: // ==IEEE: checker_or_generate_item -//UNSUP checker_or_generate_item_declaration { $$ = $1; } -//UNSUP | initial_construct { $$ = $1; } -//UNSUP // // IEEE: checker_construct -//UNSUP | yALWAYS stmtBlock { } -//UNSUP | final_construct { $$ = $1; } -//UNSUP | assertion_item { $$ = $1; } -//UNSUP | continuous_assign { $$ = $1; } -//UNSUP | checker_generate_item { $$ = $1; } -//UNSUP ; +checker_or_generate_item: // ==IEEE: checker_or_generate_item + checker_or_generate_item_declaration { $$ = $1; } + | initial_construct { $$ = $1; } + // // IEEE: checker_construct + | always_construct { $$ = $1; } + | final_construct { $$ = $1; } + | assertion_item { $$ = $1; } + | continuous_assign { $$ = $1; } + | checker_generate_item { $$ = $1; } + ; -//UNSUPchecker_or_generate_item_declaration: // ==IEEE: checker_or_generate_item_declaration -//UNSUP data_declaration { $$ = $1; } -//UNSUP | yRAND data_declaration { } -//UNSUP | function_declaration { $$ = $1; } -//UNSUP | checker_declaration { $$ = $1; } -//UNSUP | assertion_item_declaration { $$ = $1; } -//UNSUP | covergroup_declaration { $$ = $1; } -//UNSUP // // IEEE deprecated: overload_declaration -//UNSUP | genvar_declaration { $$ = $1; } -//UNSUP | clocking_declaration { $$ = $1; } -//UNSUP | yDEFAULT yCLOCKING id/*clocking_identifier*/ ';' { } -//UNSUP | yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } -//UNSUP | ';' { $$ = nullptr; } -//UNSUP ; +checker_or_generate_item_declaration: // ==IEEE: checker_or_generate_item_declaration + data_declaration + { $$ = $1; BBUNSUP($1, "Unsupported: checker data declaration"); } + | yRAND data_declaration + { $$ = $2; BBUNSUP($1, "Unsupported: checker rand"); } + | function_declaration { $$ = $1; } + | checker_declaration + { $$ = nullptr; BBUNSUP($1, "Unsupported: recursive checker"); } + | assertion_item_declaration { $$ = $1; } + //UNSUP covergroup_declaration { $$ = $1; } + // // IEEE deprecated: overload_declaration + | genvar_declaration { $$ = $1; } + | clocking_declaration { $$ = $1; } + | yDEFAULT yCLOCKING id/*clocking_identifier*/ ';' { } + { $$ = nullptr; BBUNSUP($1, "Unsupported: checker default clocking"); } + | yDEFAULT yDISABLE yIFF expr/*expression_or_dist*/ ';' { } + { $$ = nullptr; BBUNSUP($1, "Unsupported: checker default disable iff"); } + | ';' { $$ = nullptr; } + ; -//UNSUPchecker_generate_item: // ==IEEE: checker_generate_item -//UNSUP // // Specialized for checker so need "c_" prefixes here -//UNSUP c_loop_generate_construct { $$ = $1; } -//UNSUP | c_conditional_generate_construct { $$ = $1; } -//UNSUP | c_generate_region { $$ = $1; } -//UNSUP // -//UNSUP | elaboration_system_task { $$ = $1; } -//UNSUP ; +checker_generate_item: // ==IEEE: checker_generate_item + // // Specialized for checker so need "c_" prefixes here + c_loop_generate_construct { $$ = $1; } + | c_conditional_generate_construct { $$ = $1; } + | c_generate_region { $$ = $1; } + // + | elaboration_system_task { $$ = $1; } + ; //UNSUPchecker_instantiation: //UNSUP // // Only used for procedural_assertion_item's //UNSUP // // Version in concurrent_assertion_item looks like etcInst -//UNSUP // // Thus instead of *_checker_port_connection we can use etcInst's cellpinList -//UNSUP id/*checker_identifier*/ id '(' cellpinList ')' ';' { } +//UNSUP // // Thus instead of *_checker_port_connection we can use etcInst's cellpinListE +//UNSUP id/*checker_identifier*/ id '(' cellpinListE ')' ';' { } //UNSUP ; //********************************************************************** @@ -6443,11 +6622,11 @@ class_declaration: // ==IEEE: part of class_declaration } /*cont*/ class_itemListE yENDCLASS endLabelE { $$ = $1; $1->addMembersp($2); - $1->extendsp($3); - $1->addMembersp($4); + $1->addExtendsp($3); + $1->addExtendsp($4); $1->addMembersp($7); SYMP->popScope($$); - GRAMMARP->endLabel($7, $1, $9); } + GRAMMARP->endLabel($9, $1, $9); } ; classFront: // IEEE: part of class_declaration @@ -6460,9 +6639,10 @@ classFront: // IEEE: part of class_declaration // // IEEE: part of interface_class_declaration | yINTERFACE yCLASS lifetimeE idAny/*class_identifier*/ { $$ = new AstClass{$2, *$4}; + $$->isInterfaceClass(true); $$->lifetime($3); SYMP->pushNew($$); - BBUNSUP($2, "Unsupported: interface classes"); } + v3Global.setHasClasses(); } ; classVirtualE: @@ -6479,47 +6659,42 @@ classExtendsE: // IEEE: part of class_declaration classExtendsList: // IEEE: part of class_declaration classExtendsOne { $$ = $1; $$ = $1; } - | classExtendsList ',' classExtendsOne - { $$ = $3; $$ = $3; - BBUNSUP($3, "Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), " - "and unsupported for interface classes."); } + | classExtendsList ',' classExtendsOne { $$ = addNextNull($1, $3); $$ = $3; } ; classExtendsOne: // IEEE: part of class_declaration class_typeExtImpList - { $$ = new AstClassExtends{$1->fileline(), $1}; + { $$ = new AstClassExtends{$1->fileline(), $1, GRAMMARP->m_inImplements}; $$ = $1; } - // - | class_typeExtImpList '(' list_of_argumentsE ')' - { $$ = new AstClassExtends{$1->fileline(), $1}; - $$ = $1; - if ($3) BBUNSUP($3, "Unsupported: extends with parameters"); } ; -classImplementsE: // IEEE: part of class_declaration +classImplementsE: // IEEE: part of class_declaration // // All 1800-2012 - /* empty */ { $$ = nullptr; } - | yIMPLEMENTS classImplementsList { $$ = $2; } + /* empty */ { $$ = nullptr; $$ = nullptr; } + | yIMPLEMENTS + /*mid*/ { GRAMMARP->m_inImplements = true; $$ = nullptr; } + /*cont*/ classImplementsList + { $$ = $3; $$ = $3; + GRAMMARP->m_inImplements = false; } ; -classImplementsList: // IEEE: part of class_declaration +classImplementsList: // IEEE: part of class_declaration // // All 1800-2012 - class_typeExtImpList { $$ = nullptr; BBUNSUP($1, "Unsupported: implements class"); } - | classImplementsList ',' class_typeExtImpList { $$ = addNextNull($1, $3); } + classExtendsOne { $$ = $1; $$ = $1; } + | classImplementsList ',' classExtendsOne + { $$ = addNextNull($1, $3); $$ = $3; } ; -class_typeExtImpList: // IEEE: class_type: "[package_scope] id [ parameter_value_assignment ]" +class_typeExtImpList: // IEEE: class_type: "[package_scope] id [ parameter_value_assignment ]" // // but allow yaID__aTYPE for extends/implements // // If you follow the rules down, class_type is really a list via ps_class_identifier class_typeExtImpOne { $$ = $1; $$ = $1; } | class_typeExtImpList yP_COLONCOLON class_typeExtImpOne - { $$ = $3; $$ = $1; - // Cannot just add as next() as that breaks implements lists - //UNSUP $$ = new AstDot{$1, true, $1, $3}; - BBUNSUP($2, "Unsupported: Hierarchical class references"); } + { $$ = new AstDot{$1, true, $1, $3}; + $$ = $3; } ; -class_typeExtImpOne: // part of IEEE: class_type, where we either get a package_scope component or class +class_typeExtImpOne: // part of IEEE: class_type, where we either get a package_scope component or class // // If you follow the rules down, class_type is really a list via ps_class_identifier // // Not listed in IEEE, but see bug627 any parameter type maybe a class // // If idAny below is a class, parameter_value is legal @@ -6527,6 +6702,11 @@ class_typeExtImpOne: // part of IEEE: class_type, where we either get // // If idAny below is otherwise, not legal idAny /*mid*/ { /* no nextId as not refing it above this*/ } + /*cont*/ parameter_value_assignmentE + { $$ = new AstClassOrPackageRef{$1, *$1, $1, $3}; + $$ = $1; } + | idCC + /*mid*/ { /* no nextId as not refing it above this*/ } /*cont*/ parameter_value_assignmentE { $$ = new AstClassOrPackageRef{$1, *$1, $1, $3}; $$ = $1; } @@ -6776,9 +6956,10 @@ dist_item: // ==IEEE: dist_item + dist_weight | value_range yP_COLONDIV expr { $$ = $1; /*UNSUP-no-UVM*/ } ; -//UNSUPextern_constraint_declaration: // ==IEEE: extern_constraint_declaration -//UNSUP constraintStaticE yCONSTRAINT class_scope_id constraint_block { } -//UNSUP ; +extern_constraint_declaration: // ==IEEE: extern_constraint_declaration + constraintStaticE yCONSTRAINT packageClassScopeE idAny + { $$ = nullptr; BBUNSUP($2, "Unsupported: extern constraint"); } + ; constraintStaticE: // IEEE: part of extern_constraint_declaration /* empty */ { $$ = false; } diff --git a/test_regress/CMakeLists.txt b/test_regress/CMakeLists.txt index fc83ccee5..91e5eab28 100644 --- a/test_regress/CMakeLists.txt +++ b/test_regress/CMakeLists.txt @@ -12,7 +12,8 @@ # ###################################################################### -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0074 NEW) set(TEST_REQUIRED_VARS NAME CSOURCES OPT_FAST OPT_GLOBAL VERILATOR_ROOT VERILATOR_ARGS VERILATOR_SOURCES SYSTEMC VERBOSE VERILATION) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index a0c616a1f..2a1685e4e 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -676,12 +676,12 @@ sub new { $self->{vlt_all} = $self->{vlt} || $self->{vltmt}; # Any Verilator scenario - $self->{VM_PREFIX} ||= "V" . $self->{name}; + $self->{vm_prefix} ||= "V" . $self->{name}; $self->{stats} ||= "$self->{obj_dir}/V" . $self->{name} . "__stats.txt"; $self->{status_filename} ||= "$self->{obj_dir}/V" . $self->{name} . ".status"; $self->{run_log_filename} ||= "$self->{obj_dir}/vlt_sim.log"; $self->{coverage_filename} ||= "$self->{obj_dir}/coverage.dat"; - $self->{main_filename} ||= "$self->{obj_dir}/$self->{VM_PREFIX}__main.cpp"; + $self->{main_filename} ||= "$self->{obj_dir}/$self->{vm_prefix}__main.cpp"; ($self->{top_filename} ||= $self->{pl_filename}) =~ s/\.pl$//; ($self->{golden_filename} ||= $self->{pl_filename}) =~ s/\.pl$/.out/; if (-e ($self->{top_filename} . ".vhd")) { # If VHDL file exists @@ -693,7 +693,7 @@ sub new { if (!$self->{make_top_shell}) { $self->{top_shell_filename} = $self->{top_filename}; } else { - $self->{top_shell_filename} = "$self->{obj_dir}/$self->{VM_PREFIX}__top.v"; + $self->{top_shell_filename} = "$self->{obj_dir}/$self->{vm_prefix}__top.v"; } $self->{pli_filename} ||= $self->{name} . ".cpp"; @@ -926,7 +926,7 @@ sub compile_vlt_flags { $param{make_main} && $param{verilator_make_gmake}; my @cmdargs = ( - "--prefix " . $param{VM_PREFIX}, + "--prefix " . $param{vm_prefix}, @verilator_flags, @{$param{verilator_flags2}}, @{$param{verilator_flags3}}, @@ -983,7 +983,7 @@ sub compile { = $self->{top_shell_filename} = ""; } else { $param{top_shell_filename} - = $self->{top_shell_filename} = "$self->{obj_dir}/$self->{VM_PREFIX}__top." . $self->v_suffix; + = $self->{top_shell_filename} = "$self->{obj_dir}/$self->{vm_prefix}__top." . $self->v_suffix; } if ($param{atsim}) { @@ -1174,13 +1174,13 @@ sub compile { "-C " . $self->{obj_dir}, "-f " . $FindBin::RealBin . "/Makefile_obj", ($self->{verbose} ? "" : "--no-print-directory"), - "VM_PREFIX=$self->{VM_PREFIX}", + "VM_PREFIX=$self->{vm_prefix}", "TEST_OBJ_DIR=$self->{obj_dir}", "CPPFLAGS_DRIVER=-D" . uc($self->{name}), ($self->{verbose} ? "CPPFLAGS_DRIVER2=-DTEST_VERBOSE=1" : ""), ($param{benchmark} ? "" : "OPT_FAST=-O0"), ($param{benchmark} ? "" : "OPT_GLOBAL=-O0"), - "$self->{VM_PREFIX}", # bypass default rule, as we don't need archive + "$self->{vm_prefix}", # bypass default rule, as we don't need archive ($param{make_flags} || ""), ]); } @@ -1327,7 +1327,7 @@ sub execute { elsif ($param{vlt_all} #&& (!$param{needs_v4} || -r "$ENV{VERILATOR_ROOT}/src/V3Gate.cpp") ) { - $param{executable} ||= "$self->{obj_dir}/$param{VM_PREFIX}"; + $param{executable} ||= "$self->{obj_dir}/$param{vm_prefix}"; my $debugger = ""; if ($opt_gdbsim) { $debugger = ($ENV{VERILATOR_GDB} || "gdb") . " "; @@ -1549,10 +1549,10 @@ sub wno_unopthreads_for_few_cores { return ""; } -sub VM_PREFIX { +sub vm_prefix { my $self = (ref $_[0] ? shift : $Self); - $self->{VM_PREFIX} = shift if defined $_[0]; - return $self->{VM_PREFIX}; + $self->{vm_prefix} = shift if defined $_[0]; + return $self->{vm_prefix}; } #---------------------------------------------------------------------- @@ -1760,8 +1760,8 @@ sub _make_main { print $fh "#include \"verilatedos.h\"\n"; print $fh "// Generated header\n"; - my $VM_PREFIX = $self->{VM_PREFIX}; - print $fh "#include \"$VM_PREFIX.h\"\n"; + my $vm_prefix = $self->{vm_prefix}; + print $fh "#include \"${vm_prefix}.h\"\n"; print $fh "// General headers\n"; print $fh "#include \"verilated.h\"\n"; @@ -1772,7 +1772,7 @@ sub _make_main { print $fh "#include \"verilated_vcd_sc.h\"\n" if $self->{trace} && $self->{trace_format} eq 'vcd-sc'; print $fh "#include \"verilated_save.h\"\n" if $self->{savable}; - print $fh "std::unique_ptr<$VM_PREFIX> topp;\n"; + print $fh "std::unique_ptr<${vm_prefix}> topp;\n"; if ($self->{savable}) { $fh->print("\n"); @@ -1813,7 +1813,7 @@ sub _make_main { print $fh " srand48(5);\n"; # Ensure determinism print $fh " contextp->randReset(" . $self->{verilated_randReset} . ");\n" if defined $self->{verilated_randReset}; - print $fh " topp.reset(new $VM_PREFIX(\"top\"));\n"; + print $fh " topp.reset(new ${vm_prefix}(\"top\"));\n"; print $fh " contextp->internalsDump()\n;" if $self->{verilated_debug}; my $set; diff --git a/test_regress/t/TestSimulator.h b/test_regress/t/TestSimulator.h index 5c49404f4..0f3659440 100644 --- a/test_regress/t/TestSimulator.h +++ b/test_regress/t/TestSimulator.h @@ -74,7 +74,8 @@ public: static const char* rooted(const char* obj) { static std::string buf; std::ostringstream os; - os << top() << "." << obj; + os << top(); + if (*obj) os << "." << obj; buf = os.str(); return buf.c_str(); } diff --git a/test_regress/t/t_a3_selftest_thread.pl b/test_regress/t/t_a3_selftest_thread.pl new file mode 100755 index 000000000..a47da043c --- /dev/null +++ b/test_regress/t/t_a3_selftest_thread.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_EXAMPLE.v"); + +lint( + v_flags => ["--lint-only --verilate-jobs 2 --debug-self-test"], + ); + +ok(1); +1; diff --git a/test_regress/t/t_a5_attributes_src.pl b/test_regress/t/t_a5_attributes_src.pl index 8c2447820..92a4ca5d6 100755 --- a/test_regress/t/t_a5_attributes_src.pl +++ b/test_regress/t/t_a5_attributes_src.pl @@ -36,7 +36,7 @@ sub check { tee => 1, cmd => ["python3", "$root/nodist/clang_check_attributes --verilator-root=$root --cxxflags='$clang_args' $precompile_args $srcfiles_str"]); - file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 24"); + file_grep($Self->{run_log_filename}, "Number of functions reported unsafe: 27"); } run_clang_check(); diff --git a/test_regress/t/t_alw_noreorder.pl b/test_regress/t/t_alw_noreorder.pl index edc2a6f7b..c30d624bd 100755 --- a/test_regress/t/t_alw_noreorder.pl +++ b/test_regress/t/t_alw_noreorder.pl @@ -19,7 +19,7 @@ file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0); # Here we should see some dly vars since reorder is disabled. # (Whereas our twin test, t_alw_reorder, should see no dly vars # since it enables the reorder step.) -my @files = glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root*.cpp"); +my @files = glob_all("$Self->{obj_dir}/$Self->{vm_prefix}___024root*.cpp"); file_grep_any(\@files, qr/dly__t__DOT__v1/i); file_grep_any(\@files, qr/dly__t__DOT__v2/i); diff --git a/test_regress/t/t_alw_reorder.pl b/test_regress/t/t_alw_reorder.pl index 90a7126da..0c855076f 100755 --- a/test_regress/t/t_alw_reorder.pl +++ b/test_regress/t/t_alw_reorder.pl @@ -19,8 +19,8 @@ file_grep($Self->{stats}, qr/Optimizations, Split always\s+(\d+)/i, 0); # Equally important: twin test t_alw_noreorder should see dly vars, # is identical to this test except for disabling the reorder step. foreach my $file ( - glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.h"), - glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp") + glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.h"), + glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.cpp") ) { file_grep_not($file, qr/dly__t__DOT__v1/i); file_grep_not($file, qr/dly__t__DOT__v2/i); diff --git a/test_regress/t/t_array_list_bad.out b/test_regress/t/t_array_list_bad.out index 3ce83ac48..c1b3a1b46 100644 --- a/test_regress/t/t_array_list_bad.out +++ b/test_regress/t/t_array_list_bad.out @@ -2,10 +2,10 @@ : ... In instance t 38 | test_out <= '{'0, '0}; | ^~ -%Warning-WIDTH: t/t_array_list_bad.v:38:22: Operator ASSIGNDLY expects 3 bits on the Assign RHS, but Assign RHS's CONCAT generates 2 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_array_list_bad.v:38:22: Operator ASSIGNDLY expects 3 bits on the Assign RHS, but Assign RHS's CONCAT generates 2 bits. + : ... In instance t 38 | test_out <= '{'0, '0}; | ^~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_assert_disabled.pl b/test_regress/t/t_assert_disabled.pl index 1b8f06b8b..812f91229 100755 --- a/test_regress/t/t_assert_disabled.pl +++ b/test_regress/t/t_assert_disabled.pl @@ -14,7 +14,9 @@ top_filename("t/t_assert_on.v"); compile(); -execute(); +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_assert_named_property.v b/test_regress/t/t_assert_named_property.v index 43a41582f..36e622825 100644 --- a/test_regress/t/t_assert_named_property.v +++ b/test_regress/t/t_assert_named_property.v @@ -22,11 +22,13 @@ module t (/*AUTOARG*/ cyc % 2 == cyc_mod_2 |=> val == expected; endproperty - property check_if_1(int cyc_mod_2); + // Also checks parsing 'var datatype' + property check_if_1(var int cyc_mod_2); check(cyc_mod_2, 1); endproperty - property check_if_gt_5(int cyc); + // Also checks parsing 'signing range' + property check_if_gt_5(signed [31:0] cyc); @(posedge clk) cyc > 5; endproperty diff --git a/test_regress/t/t_assert_on.v b/test_regress/t/t_assert_on.v index 55704fa6b..a1b28e48b 100644 --- a/test_regress/t/t_assert_on.v +++ b/test_regress/t/t_assert_on.v @@ -13,6 +13,7 @@ module t (/*AUTOARG*/ always @ (posedge clk) begin assert (0); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_assert_procedural_clk.out b/test_regress/t/t_assert_procedural_clk.out new file mode 100644 index 000000000..8d930ad07 --- /dev/null +++ b/test_regress/t/t_assert_procedural_clk.out @@ -0,0 +1,9 @@ +%Error: t/t_assert_procedural_clk.v:21:13: Unsupported: Procedural concurent assertion with clocking event inside always (IEEE 1800-2917 16.14.6) + : ... In instance t + 21 | assume property (@(posedge clk) cyc == 9); + | ^~~~~~ +%Error: t/t_assert_procedural_clk.v:22:13: Unsupported: Procedural concurent assertion with clocking event inside always (IEEE 1800-2917 16.14.6) + : ... In instance t + 22 | assume property (@(negedge clk) cyc == 9); + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_cdc_async_debug_bad.pl b/test_regress/t/t_assert_procedural_clk.pl similarity index 56% rename from test_regress/t/t_cdc_async_debug_bad.pl rename to test_regress/t/t_assert_procedural_clk.pl index 5634177a8..d188a4276 100755 --- a/test_regress/t/t_cdc_async_debug_bad.pl +++ b/test_regress/t/t_assert_procedural_clk.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2009 by Wilson Snyder. This program is free software; you +# Copyright 2022 by Wilson Snyder. This program is free software; you # can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. @@ -10,18 +10,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -top_filename("t/t_cdc_async_bad.v"); - compile( - # --debug so we get code coverage of Cdc - v_flags => ['--cdc --debug'], - verilator_make_gmake => 0, - make_top_shell => 0, - make_main => 0, + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--assert'], fails => 1, ); -files_identical("$Self->{obj_dir}/V$Self->{name}__cdc_edges.txt", $Self->{golden_filename}); - ok(1); 1; diff --git a/test_regress/t/t_assert_procedural_clk.v b/test_regress/t/t_assert_procedural_clk.v new file mode 100644 index 000000000..ef2220d7f --- /dev/null +++ b/test_regress/t/t_assert_procedural_clk.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + integer cyc; initial cyc=1; + wire [7:0] cyc_copy = cyc[7:0]; + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + if (cyc==9) begin + assume property (@(posedge clk) cyc == 9); + assume property (@(negedge clk) cyc == 9); + end + if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + +endmodule diff --git a/test_regress/t/t_c_this.pl b/test_regress/t/t_c_this.pl index 93c3b5200..7fa144221 100755 --- a/test_regress/t/t_c_this.pl +++ b/test_regress/t/t_c_this.pl @@ -19,7 +19,7 @@ if ($Self->{vlt_all}) { my $has_xthis = 0; my $has_thisx = 0; my $has_xthisx = 0; - for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__DepSet_*__0.cpp")) { + for my $file (glob_all("$Self->{obj_dir}/$Self->{vm_prefix}___024root__DepSet_*__0.cpp")) { my $text = file_contents($file); $has_this = 1 if ($text =~ m/\bthis->clk\b/); $has_xthis = 1 if ($text =~ m/\bxthis\b/); diff --git a/test_regress/t/t_case_enum_emptyish.v b/test_regress/t/t_case_enum_emptyish.v index 0dbeb259a..91fc001bc 100644 --- a/test_regress/t/t_case_enum_emptyish.v +++ b/test_regress/t/t_case_enum_emptyish.v @@ -10,7 +10,7 @@ module t (/*AUTOARG*/); e0, e1, e2, - e3 + e3 } EN; initial begin diff --git a/test_regress/t/t_case_write1_tasks.v b/test_regress/t/t_case_write1_tasks.v index be868734c..07ce93190 100644 --- a/test_regress/t/t_case_write1_tasks.v +++ b/test_regress/t/t_case_write1_tasks.v @@ -2066,7 +2066,7 @@ module t_case_write1_tasks (); endcase end endtask - task ozonef3; + task automatic ozonef3; input [ 31:0] foo; inout [STRLEN*8: 1] foobar; reg nacho; @@ -2475,7 +2475,7 @@ module t_case_write1_tasks (); endcase end endtask - task dude; + task automatic dude; inout [STRLEN*8: 1] foobar; reg [ 7:0] temp; integer i; @@ -2497,7 +2497,7 @@ module t_case_write1_tasks (); end endtask - task big_case; + task automatic big_case; input [ 31:0] fd; input [ 31:0] foo; reg [STRLEN*8: 1] foobar; diff --git a/test_regress/t/t_case_write2_tasks.v b/test_regress/t/t_case_write2_tasks.v index cae09726e..ebd12bdb3 100644 --- a/test_regress/t/t_case_write2_tasks.v +++ b/test_regress/t/t_case_write2_tasks.v @@ -2067,7 +2067,7 @@ module t_case_write2_tasks (); endcase end endtask - task ozonef3; + task automatic ozonef3; input [ 31:0] foo; input [`FD_BITS] fd; reg nacho; @@ -2482,7 +2482,7 @@ module t_case_write2_tasks (); $fwrite(fd," dude"); endtask - task big_case; + task automatic big_case; input [ `FD_BITS] fd; input [ 31:0] foo; // verilator no_inline_task diff --git a/test_regress/t/t_ccache_report.pl b/test_regress/t/t_ccache_report.pl index 790bbf9f0..90c5004a2 100755 --- a/test_regress/t/t_ccache_report.pl +++ b/test_regress/t/t_ccache_report.pl @@ -27,7 +27,7 @@ else { make_flags => "ccache-report" ); - my $report = "$Self->{obj_dir}/$Self->{VM_PREFIX}__ccache_report.txt"; + my $report = "$Self->{obj_dir}/$Self->{vm_prefix}__ccache_report.txt"; # We do not actually want to make this test depend on whether the file was # cached or not, so trim the report to ignore actual caching behaviour @@ -38,8 +38,8 @@ else { run( logfile => "$Self->{obj_dir}/rebuild.log", cmd => ["make", "-C", $Self->{obj_dir}, - "-f", "$Self->{VM_PREFIX}.mk", - $Self->{VM_PREFIX}, "ccache-report"] + "-f", "$Self->{vm_prefix}.mk", + $Self->{vm_prefix}, "ccache-report"] ); files_identical($report, "t/$Self->{name}__ccache_report_rebuild.out"); diff --git a/test_regress/t/t_cdc_async_bad.out b/test_regress/t/t_cdc_async_bad.out deleted file mode 100644 index 3d767fbe4..000000000 --- a/test_regress/t/t_cdc_async_bad.out +++ /dev/null @@ -1,14 +0,0 @@ -%Warning-DEPRECATED: Option --cdc is deprecated and is planned for removal - ... For warning description see https://verilator.org/warn/DEPRECATED?v=latest - ... Use "/* verilator lint_off DEPRECATED */" and lint_on around source to disable this message. -%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:53:21: Logic in path that feeds async reset, via signal: 't.rst6a_bad_n' - 53 | wire rst6a_bad_n = rst6_bad_n ^ $c1("0"); - | ^ -%Warning-CDCRSTLOGIC: See details in obj_vlt/t_cdc_async_bad/Vt_cdc_async_bad__cdc.txt -%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:54:21: Logic in path that feeds async reset, via signal: 't.rst6b_bad_n' - 54 | wire rst6b_bad_n = rst6_bad_n ^ $c1("1"); - | ^ -%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:28:21: Logic in path that feeds async reset, via signal: 't.rst2_bad_n' - 28 | wire rst2_bad_n = rst0_n | rst1_n; - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_cdc_async_bad.v b/test_regress/t/t_cdc_async_bad.v deleted file mode 100644 index 5a9dd3c9a..000000000 --- a/test_regress/t/t_cdc_async_bad.v +++ /dev/null @@ -1,82 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2009 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (/*AUTOARG*/ - // Outputs - q0, q1, q2, q3, q4, q5, q6a, q6b, - // Inputs - clk, d, rst0_n - ); - input clk; - input d; - - // OK -- from primary - input rst0_n; - output wire q0; - Flop flop0 (.q(q0), .rst_n(rst0_n), .clk(clk), .d(d)); - - // OK -- from flop - reg rst1_n; - always @ (posedge clk) rst1_n <= rst0_n; - output wire q1; - Flop flop1 (.q(q1), .rst_n(rst1_n), .clk(clk), .d(d)); - - // Bad - logic - wire rst2_bad_n = rst0_n | rst1_n; - output wire q2; - Flop flop2 (.q(q2), .rst_n(rst2_bad_n), .clk(clk), .d(d)); - - // Bad - logic in submodule - wire rst3_bad_n; - Sub sub (.z(rst3_bad_n), .a(rst0_n), .b(rst1_n)); - output wire q3; - Flop flop3 (.q(q3), .rst_n(rst3_bad_n), .clk(clk), .d(d)); - - // OK - bit selection - reg [3:0] rst4_n; - always @ (posedge clk) rst4_n <= {4{rst0_n}}; - output wire q4; - Flop flop4 (.q(q4), .rst_n(rst4_n[1]), .clk(clk), .d(d)); - - // Bad - logic, but waived - // verilator lint_off CDCRSTLOGIC - wire rst5_waive_n = rst0_n & rst1_n; - // verilator lint_on CDCRSTLOGIC - output wire q5; - Flop flop5 (.q(q5), .rst_n(rst5_waive_n), .clk(clk), .d(d)); - - // Bad - for graph test - logic feeds two signals, three destinations - wire rst6_bad_n = rst0_n ^ rst1_n; - wire rst6a_bad_n = rst6_bad_n ^ $c1("0"); // $c prevents optimization - wire rst6b_bad_n = rst6_bad_n ^ $c1("1"); - output wire q6a; - output wire q6b; - Flop flop6a (.q(q6a), .rst_n(rst6a_bad_n), .clk(clk), .d(d)); - Flop flop6v (.q(q6b), .rst_n(rst6b_bad_n), .clk(clk), .d(d)); - - initial begin - $display("%%Error: Not a runnable test"); - $stop; - end - -endmodule - -module Flop ( - input clk, - input d, - input rst_n, - output logic q); - - always @ (posedge clk or negedge rst_n) begin - if (!rst_n) q <= 1'b0; - else q <= d; - end -endmodule - -module Sub (input a, b, - output z); - assign z = a|b; -endmodule diff --git a/test_regress/t/t_cdc_async_debug_bad.out b/test_regress/t/t_cdc_async_debug_bad.out deleted file mode 100644 index 2a6956531..000000000 --- a/test_regress/t/t_cdc_async_debug_bad.out +++ /dev/null @@ -1,20 +0,0 @@ -Edge Report for Vt_cdc_async_debug_bad - t_cdc_async_bad.v: input clk SRC=@(*) DST=@(posedge clk or negedge rst0_n or negedge t.__Vcellinp__flop4__rst_n or negedge t.rst1_n or negedge t.rst2_bad_n or negedge t.rst5_waive_n or negedge t.rst6a_bad_n or negedge t.rst6b_bad_n) - t_cdc_async_bad.v: input d SRC=@(*) DST=@(posedge clk or negedge rst0_n or negedge t.__Vcellinp__flop4__rst_n or negedge t.rst1_n or negedge t.rst2_bad_n or negedge t.rst5_waive_n or negedge t.rst6a_bad_n or negedge t.rst6b_bad_n) - t_cdc_async_bad.v: input rst0_n SRC=@(*) DST=@(posedge clk or negedge rst0_n or negedge t.rst2_bad_n or negedge t.rst5_waive_n or negedge t.rst6a_bad_n or negedge t.rst6b_bad_n) - t_cdc_async_bad.v: output q0 SRC=@(posedge clk or negedge rst0_n) DST= - t_cdc_async_bad.v: output q1 SRC=@(posedge clk or negedge t.rst1_n) DST= - t_cdc_async_bad.v: output q2 SRC=@(posedge clk or negedge t.rst2_bad_n) DST= - t_cdc_async_bad.v: output q3 SRC=@(posedge clk or negedge t.rst2_bad_n) DST= - t_cdc_async_bad.v: output q4 SRC=@(posedge clk or negedge t.__Vcellinp__flop4__rst_n) DST= - t_cdc_async_bad.v: output q5 SRC=@(posedge clk or negedge t.rst5_waive_n) DST= - t_cdc_async_bad.v: output q6a SRC=@(posedge clk or negedge t.rst6a_bad_n) DST= - t_cdc_async_bad.v: output q6b SRC=@(posedge clk or negedge t.rst6b_bad_n) DST= - t_cdc_async_bad.v: wire t.__Vcellinp__flop4__rst_n SRC=@(posedge clk) DST=@(posedge clk or negedge t.__Vcellinp__flop4__rst_n) - t_cdc_async_bad.v: wire t.rst1_n SRC=@(posedge clk) DST=@(posedge clk or negedge t.rst1_n or negedge t.rst2_bad_n or negedge t.rst5_waive_n or negedge t.rst6a_bad_n or negedge t.rst6b_bad_n) - t_cdc_async_bad.v: wire t.rst2_bad_n SRC=@(* or posedge clk) DST=@(posedge clk or negedge t.rst2_bad_n) - t_cdc_async_bad.v: wire t.rst4_n SRC=@(posedge clk) DST=@(posedge clk or negedge t.__Vcellinp__flop4__rst_n) - t_cdc_async_bad.v: wire t.rst5_waive_n SRC=@(* or posedge clk) DST=@(posedge clk or negedge t.rst5_waive_n) - t_cdc_async_bad.v: wire t.rst6_bad_n SRC=@(* or posedge clk) DST=@(posedge clk or negedge t.rst6a_bad_n or negedge t.rst6b_bad_n) - t_cdc_async_bad.v: wire t.rst6a_bad_n SRC=@(* or posedge clk) DST=@(posedge clk or negedge t.rst6a_bad_n) - t_cdc_async_bad.v: wire t.rst6b_bad_n SRC=@(* or posedge clk) DST=@(posedge clk or negedge t.rst6b_bad_n) diff --git a/test_regress/t/t_checker.out b/test_regress/t/t_checker.out new file mode 100644 index 000000000..b64cf2a82 --- /dev/null +++ b/test_regress/t/t_checker.out @@ -0,0 +1,38 @@ +%Error-UNSUPPORTED: t/t_checker.v:33:1: Unsupported: checker + 33 | checker Chk + | ^~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_checker.v:36:8: Unsupported: checker data declaration + 36 | bit clk; + | ^~~ +%Error-UNSUPPORTED: t/t_checker.v:37:8: Unsupported: checker data declaration + 37 | bit in; + | ^~ +%Error-UNSUPPORTED: t/t_checker.v:38:8: Unsupported: checker data declaration + 38 | bit rst; + | ^~~ +%Error-UNSUPPORTED: t/t_checker.v:39:4: Unsupported: checker rand + 39 | rand bit randed; + | ^~~~ +%Error-UNSUPPORTED: t/t_checker.v:41:8: Unsupported: checker data declaration + 41 | int counter = 0; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_checker.v:43:8: Unsupported: checker data declaration + 43 | int ival; + | ^~~~ +%Error-UNSUPPORTED: t/t_checker.v:53:8: Unsupported: checker data declaration + 53 | int ival2; + | ^~~~~ +%Error-UNSUPPORTED: t/t_checker.v:61:4: Unsupported: checker default clocking + 61 | default clocking clk; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_checker.v:62:4: Unsupported: checker default disable iff + 62 | default disable iff rst; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_checker.v:64:4: Unsupported: checker + 64 | checker ChkChk; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_checker.v:64:12: Unsupported: recursive checker + 64 | checker ChkChk; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_cdc_async_bad.pl b/test_regress/t/t_checker.pl similarity index 68% rename from test_regress/t/t_cdc_async_bad.pl rename to test_regress/t/t_checker.pl index d1b47ec05..1ce0595d2 100755 --- a/test_regress/t/t_cdc_async_bad.pl +++ b/test_regress/t/t_checker.pl @@ -2,7 +2,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } # DESCRIPTION: Verilator: Verilog Test driver/expect definition # -# Copyright 2009 by Wilson Snyder. This program is free software; you +# Copyright 2023 by Wilson Snyder. This program is free software; you # can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. @@ -11,15 +11,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); compile( - v_flags => ['--cdc'], - verilator_make_gmake => 0, - make_top_shell => 0, - make_main => 0, - fails => 1, + verilator_flags2 => ['--assert'], expect_filename => $Self->{golden_filename}, + fails => 1, ); -file_grep("$Self->{obj_dir}/V$Self->{name}__cdc.txt", qr/CDC Report/); +#execute( +# check_finished => 1, +# ); ok(1); 1; diff --git a/test_regress/t/t_checker.v b/test_regress/t/t_checker.v new file mode 100644 index 000000000..12ef18bac --- /dev/null +++ b/test_regress/t/t_checker.v @@ -0,0 +1,80 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d\n", $time, cyc); +`endif + cyc <= cyc + 1; + if (cyc == 0) begin + end + else if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + + Chk check(clk, cyc); + +endmodule + +checker Chk + // UNSUP (input clk, int in) + ; + bit clk; + bit in; + bit rst; + rand bit randed; // TODO test this + + int counter = 0; + + int ival; + final if (ival != 1234) $stop; + genvar g; + if (0) begin + initial ival = 1; + end + else begin + initial ival = 1234; + end + + int ival2; + case (1) + 0: initial ival2 = 0; + default: initial ival2 = 12345; + endcase + final if (ival2 != 12345) $stop; + + + default clocking clk; // TODO test this + default disable iff rst; // TODO test this + + checker ChkChk; // TODO flag unsupported + endchecker + + function automatic int f; // TODO test this + endfunction + + + clocking cb1 @(posedge clk); // TODO test this + input in; + output out; + endclocking + + always_ff @(posedge clk) + counter <= counter + 1'b1; + + a1: assert property (@(posedge clk) counter == in); +endchecker diff --git a/test_regress/t/t_class_extends2.out b/test_regress/t/t_class_extends2.out new file mode 100644 index 000000000..9b587f905 --- /dev/null +++ b/test_regress/t/t_class_extends2.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_class_extends2.v:18:19: Unsupported: Hierarchical class references + 18 | class Ext extends Pkg::Base0; + | ^~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends2.pl b/test_regress/t/t_class_extends2.pl new file mode 100755 index 000000000..8a9b721f2 --- /dev/null +++ b/test_regress/t/t_class_extends2.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => $Self->{vlt}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends2.v b/test_regress/t/t_class_extends2.v new file mode 100644 index 000000000..8c30f0c6b --- /dev/null +++ b/test_regress/t/t_class_extends2.v @@ -0,0 +1,47 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +package Pkg; +class Base0; + int baseonly; + int baseover; + + function void b_set_bo(int v); baseover = v; endfunction + function int b_get_bo(); return baseover; endfunction + function int get_bo(); return baseover; endfunction +endclass +endpackage + +class Ext extends Pkg::Base0; + int baseover; + int extonly; + + function void e_set_bo(int v); baseover = v; endfunction + function int e_get_bo(); return baseover; endfunction + function int get_bo(); return baseover; endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + Ext c; + c = new; + c.baseonly = 10; + c.baseover = 20; + c.extonly = 30; + if (c.baseonly != 10) $stop; + if (c.baseover != 20) $stop; + if (c.extonly != 30) $stop; + + c.b_set_bo(100); + c.e_set_bo(200); + if (c.b_get_bo() != 100) $stop; + if (c.e_get_bo() != 200) $stop; + if (c.get_bo() != 200) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_extends_alias_unsup.out b/test_regress/t/t_class_extends_alias_unsup.out new file mode 100644 index 000000000..ff50572f7 --- /dev/null +++ b/test_regress/t/t_class_extends_alias_unsup.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_class_extends_alias_unsup.v:22:22: Unsupported: TYPEDEF 'foo_t' in AstClassExtends + 22 | class bar extends foo_t; + | ^~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_alias_unsup.pl b/test_regress/t/t_class_extends_alias_unsup.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_class_extends_alias_unsup.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_alias_unsup.v b/test_regress/t/t_class_extends_alias_unsup.v new file mode 100644 index 000000000..a0a8f7197 --- /dev/null +++ b/test_regress/t/t_class_extends_alias_unsup.v @@ -0,0 +1,38 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + ); + + class foo; + int x = 1; + function int get_x; + return x; + endfunction + function int get_3; + return 3; + endfunction + endclass + + typedef foo foo_t; + + class bar extends foo_t; + endclass + + + bar bar_foo_t_i; + + initial begin + bar_foo_t_i = new; + if (bar_foo_t_i.get_x() == 1 && bar_foo_t_i.get_3() == 3) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $stop; + end + end +endmodule diff --git a/test_regress/t/t_class_extends_aliased_real_bad.out b/test_regress/t/t_class_extends_aliased_real_bad.out new file mode 100644 index 000000000..ce714742d --- /dev/null +++ b/test_regress/t/t_class_extends_aliased_real_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_class_extends_aliased_real_bad.v:14:10: Attempting to extend using non-class + : ... In instance t + 14 | bar #(real_t) bar_real_t; + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_aliased_real_bad.pl b/test_regress/t/t_class_extends_aliased_real_bad.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_class_extends_aliased_real_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_aliased_real_bad.v b/test_regress/t/t_class_extends_aliased_real_bad.v new file mode 100644 index 000000000..a03f8bc93 --- /dev/null +++ b/test_regress/t/t_class_extends_aliased_real_bad.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + class bar #(type T) extends T; + endclass + + typedef real real_t; + + bar #(real_t) bar_real_t; + + initial begin + $stop; + end +endmodule diff --git a/test_regress/t/t_class_extends_bad.out b/test_regress/t/t_class_extends_bad.out index eed5066dd..468fdb3a7 100644 --- a/test_regress/t/t_class_extends_bad.out +++ b/test_regress/t/t_class_extends_bad.out @@ -1,5 +1,4 @@ -%Error-UNSUPPORTED: t/t_class_extends_bad.v:13:26: Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13), and unsupported for interface classes. +%Error: t/t_class_extends_bad.v:13:26: Multiple inheritance illegal on non-interface classes (IEEE 1800-2017 8.13) 13 | class Cls extends Base1, Base2; | ^~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_class_extends_colon.out b/test_regress/t/t_class_extends_colon.out new file mode 100644 index 000000000..ae67bbf79 --- /dev/null +++ b/test_regress/t/t_class_extends_colon.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_class_extends_colon.v:20:21: Unsupported: Hierarchical class references + 20 | class Cls12 extends Pkg::Icls1; + | ^~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_colon.pl b/test_regress/t/t_class_extends_colon.pl new file mode 100755 index 000000000..8a9b721f2 --- /dev/null +++ b/test_regress/t/t_class_extends_colon.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => $Self->{vlt}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_colon.v b/test_regress/t/t_class_extends_colon.v new file mode 100644 index 000000000..cf4fea9a0 --- /dev/null +++ b/test_regress/t/t_class_extends_colon.v @@ -0,0 +1,35 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +interface class Icempty; +endclass : Icempty + +package Pkg; +class Icls1 #(parameter PARAM = 12); + localparam LP1 = 1; + function int getParam(); + return PARAM; + endfunction +endclass + +endpackage + +class Cls12 extends Pkg::Icls1; +endclass + +module t(/*AUTOARG*/); + + Cls12 cp12; + + initial begin + cp12 = new; + if (cp12.getParam() != 12) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_class_extends_int_param_bad.out b/test_regress/t/t_class_extends_int_param_bad.out new file mode 100644 index 000000000..8f75bf3af --- /dev/null +++ b/test_regress/t/t_class_extends_int_param_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_class_extends_int_param_bad.v:9:23: Attempting to extend using non-class + : ... In instance t + 9 | class bar #(type T=int) extends T; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_int_param_bad.pl b/test_regress/t/t_class_extends_int_param_bad.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_class_extends_int_param_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_int_param_bad.v b/test_regress/t/t_class_extends_int_param_bad.v new file mode 100644 index 000000000..f5ee566eb --- /dev/null +++ b/test_regress/t/t_class_extends_int_param_bad.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + class bar #(type T=int) extends T; + endclass + + initial begin + $stop; + end +endmodule diff --git a/test_regress/t/t_class_extends_nf_bad.out b/test_regress/t/t_class_extends_nf_bad.out index 62fc4e306..d01cc3eea 100644 --- a/test_regress/t/t_class_extends_nf_bad.out +++ b/test_regress/t/t_class_extends_nf_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_class_extends_nf_bad.v:10:19: Class to extend not found: 'IsNotFound' +%Error: t/t_class_extends_nf_bad.v:10:19: Class for 'extends' not found: 'IsNotFound' : ... Suggested alternative: 'IsFound' 10 | class Cls extends IsNotFound; | ^~~~~~~~~~ diff --git a/test_regress/t/t_class_extends_param.pl b/test_regress/t/t_class_extends_param.pl new file mode 100755 index 000000000..e191e87f4 --- /dev/null +++ b/test_regress/t/t_class_extends_param.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile(); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_param.v b/test_regress/t/t_class_extends_param.v new file mode 100644 index 000000000..0d5e8cf36 --- /dev/null +++ b/test_regress/t/t_class_extends_param.v @@ -0,0 +1,60 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + ); + + class Foo; + int x = 1; + function int get_x; + return x; + endfunction + function int get_3; + return 3; + endfunction + endclass + + class Bar #(type T=Foo) extends T; + endclass + + class Baz; + int x = 2; + function int get_x; + return x; + endfunction + function int get_4; + return 4; + endfunction + endclass + + class ExtendBar extends Bar; + function int get_x; + return super.get_x(); + endfunction + function int get_6; + return 2 * get_3(); + endfunction + endclass + + Bar bar_foo_i; + Bar #(Baz) bar_baz_i; + ExtendBar extend_bar_i; + + initial begin + bar_foo_i = new; + bar_baz_i = new; + extend_bar_i = new; + if (bar_foo_i.get_x() == 1 && bar_foo_i.get_3() == 3 && + bar_baz_i.get_x() == 2 && bar_baz_i.get_4() == 4 && + extend_bar_i.get_x() == 1 && extend_bar_i.get_6() == 6) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $stop; + end + end +endmodule diff --git a/test_regress/t/t_class_extern_bad.out b/test_regress/t/t_class_extern_bad.out index e324308c0..96a3e2bb1 100644 --- a/test_regress/t/t_class_extern_bad.out +++ b/test_regress/t/t_class_extern_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_class_extern_bad.v:9:16: Duplicate declaration of task: 'nodef' +%Error: t/t_class_extern_bad.v:9:16: Duplicate declaration of task: 'extern nodef' 9 | extern task nodef(); | ^~~~~ t/t_class_extern_bad.v:8:16: ... Location of original declaration diff --git a/test_regress/t/t_class_member_bad.out b/test_regress/t/t_class_member_bad.out index 6488c1673..49570f53f 100644 --- a/test_regress/t/t_class_member_bad.out +++ b/test_regress/t/t_class_member_bad.out @@ -3,10 +3,10 @@ : ... Suggested alternative: 'memb2' 18 | c.memb3 = 3; | ^~~~~ -%Warning-WIDTH: t/t_class_member_bad.v:18:15: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '?32?sh3' generates 32 or 2 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_class_member_bad.v:18:15: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '?32?sh3' generates 32 or 2 bits. + : ... In instance t 18 | c.memb3 = 3; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_class_param.v b/test_regress/t/t_class_param.v index 5dfa4ee20..d0fc116f7 100644 --- a/test_regress/t/t_class_param.v +++ b/test_regress/t/t_class_param.v @@ -54,6 +54,72 @@ class SelfRefClassIntParam #(int P=1); typedef SelfRefClassIntParam #(10) self_int_t; endclass +class Sum #(type T); + static int sum; + static function void add(T element); + sum += int'(element); + endfunction +endclass + +class IntQueue; + int q[$]; + function int getSum(); + foreach(q[i]) + Sum#(int)::add(q[i]); + return Sum#(int)::sum; + endfunction +endclass + +class ClsStatic; + static int x = 1; + static function int get_2; + return 2; + endfunction +endclass + +class ClsParam #(type T); + typedef T param_t; +endclass + +class ClsWithParamField; + int m_field = Sum#(int)::sum; + int m_queue[$]; + + function int get(int index); + return m_queue[index]; + endfunction +endclass + +class DictWrapper; + int m_dict[string]; +endclass + +class DictOperator #(type T) extends T; + function void set(string s, int x); + m_dict[s] = x; + endfunction + + function int get(string s); + return m_dict[s]; + endfunction +endclass + +class Getter1 #(int T=0); + static function int get_1(); + return Getter1#(1)::T; + endfunction +endclass + +class Getter2 #(int T=5); + static function int get_T(); + return T; + endfunction + + static function int get_2(); + return Getter2#(2)::get_T(); + endfunction +endclass + module t (/*AUTOARG*/); Cls c12; @@ -65,6 +131,13 @@ module t (/*AUTOARG*/); SelfRefClassTypeParam::self_int_t src_int; SelfRefClassIntParam src1; SelfRefClassIntParam::self_int_t src10; + IntQueue qi; + ClsWithParamField cls_param_field; + DictOperator #(DictWrapper) dict_op; + Getter1 getter1; + Getter1 #(1) getter1_param_1; + Getter2 getter2; + int arr [1:0] = '{1, 2}; initial begin c12 = new; c4 = new; @@ -75,6 +148,13 @@ module t (/*AUTOARG*/); src_logic = new; src1 = new; src10 = new; + qi = new; + cls_param_field = new; + dict_op = new; + getter1 = new; + getter1_param_1 = new; + getter2 = new; + if (Cls#()::PBASE != 12) $stop; if (Cls#(4)::PBASE != 4) $stop; if (Cls8_t::PBASE != 8) $stop; @@ -114,6 +194,29 @@ module t (/*AUTOARG*/); if (src1.P != 1) $stop; if (src10.P != 10) $stop; + qi.q = '{2, 4, 6, 0, 2}; + if (qi.getSum() != 14) $stop; + Sum#(int)::add(arr[0]); + if(Sum#(int)::sum != 16) $stop; + if(Sum#(real)::sum != 0) $stop; + + if (ClsParam#(ClsStatic)::param_t::x != 1) $stop; + if (ClsParam#(ClsStatic)::param_t::get_2() != 2) $stop; + + cls_param_field.m_queue = '{1, 5, 7}; + if (cls_param_field.get(2) != 7) $stop; + + dict_op.set("abcd", 1); + if(dict_op.get("abcd") != 1) $stop; + + if (getter1.get_1() != 1) $stop; + if (Getter1#()::get_1() != 1) $stop; + if (getter1_param_1.get_1() != 1) $stop; + + if (getter2.get_2() != 2) $stop; + if (Getter2#()::get_2() != 2) $stop; + if (Getter2#(2)::get_2() != 2) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_param_bad_paren.out b/test_regress/t/t_class_param_bad_paren.out new file mode 100644 index 000000000..8de97f3d9 --- /dev/null +++ b/test_regress/t/t_class_param_bad_paren.out @@ -0,0 +1,5 @@ +%Error: t/t_class_param_bad_paren.v:28:11: Reference to parameterized class without #() (IEEE 1800-2017 8.25.1) + : ... Suggest use 'Cls#()' + 28 | if (Cls::OTHER != 12) $stop; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_param_bad_paren.pl b/test_regress/t/t_class_param_bad_paren.pl new file mode 100755 index 000000000..44783b1f6 --- /dev/null +++ b/test_regress/t/t_class_param_bad_paren.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_bad_paren.v b/test_regress/t/t_class_param_bad_paren.v new file mode 100644 index 000000000..e81209326 --- /dev/null +++ b/test_regress/t/t_class_param_bad_paren.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Cls #(int PARAM = 1); + parameter OTHER = 12; +endclass + +class Other extends Cls#(); // Ok +endclass + +class OtherMaybe extends Cls; // Questionable but others do not warn +endclass + +module t (/*AUTOARG*/); + + typedef Cls#(2) Cls2_t; // Ok + typedef Cls ClsNone_t; // Ok + + Cls c; // Ok + + initial begin + if (Cls#()::OTHER != 12) $stop; // Ok + if (Cls2_t::OTHER != 12) $stop; // ok + + if (Cls::OTHER != 12) $stop; // Bad #() required + end + +endmodule diff --git a/test_regress/t/t_class_param_noinit.pl b/test_regress/t/t_class_param_noinit.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_class_param_noinit.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_noinit.v b/test_regress/t/t_class_param_noinit.v new file mode 100644 index 000000000..92a1f7df6 --- /dev/null +++ b/test_regress/t/t_class_param_noinit.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// No init value is legal with classes, as long as not used without the parameter +class Cls #(int A, int B); +endclass + +module t(/*AUTOARG*/); + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_class_param_noinit_bad.out b/test_regress/t/t_class_param_noinit_bad.out new file mode 100644 index 000000000..7e021c7b9 --- /dev/null +++ b/test_regress/t/t_class_param_noinit_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_class_param_noinit_bad.v:13:7: Class parameter without initial value is never given value (IEEE 1800-2017 6.20.1): 'B' + : ... In instance t + 13 | Cls #(1) c; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_param_noinit_bad.pl b/test_regress/t/t_class_param_noinit_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_class_param_noinit_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_noinit_bad.v b/test_regress/t/t_class_param_noinit_bad.v new file mode 100644 index 000000000..52398d589 --- /dev/null +++ b/test_regress/t/t_class_param_noinit_bad.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// No init value is legal with classes, as long as not used without the parameter +class Cls #(int A, int B); +endclass + +module t(/*AUTOARG*/); + initial begin + Cls #(1) c; // Bad: missing B + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_class_static.out b/test_regress/t/t_class_static.out deleted file mode 100644 index 927221b52..000000000 --- a/test_regress/t/t_class_static.out +++ /dev/null @@ -1,6 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_static.v:25:18: Unsupported: 'static' function/task variables - : ... In instance t - 25 | static int st = 2; st++; return st; - | ^~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_class_static.pl b/test_regress/t/t_class_static.pl index 8d48ddb75..b46d46042 100755 --- a/test_regress/t/t_class_static.pl +++ b/test_regress/t/t_class_static.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, # Verilator unsupported, bug546 - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_clk_concat.pl b/test_regress/t/t_clk_concat.pl index 6506f7873..8c428d0ed 100755 --- a/test_regress/t/t_clk_concat.pl +++ b/test_regress/t/t_clk_concat.pl @@ -17,9 +17,9 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_clk_concat_vlt.pl b/test_regress/t/t_clk_concat_vlt.pl index aada588d7..09411f6ca 100755 --- a/test_regress/t/t_clk_concat_vlt.pl +++ b/test_regress/t/t_clk_concat_vlt.pl @@ -18,10 +18,10 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_clk_inp_init.cpp b/test_regress/t/t_clk_inp_init.cpp index c80c819a3..6afcc98ce 100644 --- a/test_regress/t/t_clk_inp_init.cpp +++ b/test_regress/t/t_clk_inp_init.cpp @@ -24,7 +24,7 @@ void oneTest(int argc, char** argv, int seed) { contextp->randReset(123); // Construct the Verilated model, from Vtop.h generated from Verilating - const std::unique_ptr topp{new Vt_clk_inp_init{contextp.get()}}; + const std::unique_ptr topp{new VM_PREFIX{contextp.get()}}; // Start not in reset topp->rst_n = 1; diff --git a/test_regress/t/t_clocking_bad5.out b/test_regress/t/t_clocking_bad5.out new file mode 100644 index 000000000..487c4450e --- /dev/null +++ b/test_regress/t/t_clocking_bad5.out @@ -0,0 +1,22 @@ +%Error: t/t_clocking_bad5.v:29:20: Duplicate declaration of CLOCKING 'ck': '$global_clock' + 29 | global clocking ogck @(posedge clk); endclocking + | ^~~~ + t/t_clocking_bad5.v:26:20: ... Location of original declaration + 26 | global clocking ck @(posedge clk); endclocking + | ^~ +%Error: t/t_clocking_bad5.v:32:20: Duplicate declaration of CLOCKING 'ogck': '$global_clock' + 32 | global clocking ck @(posedge clk); endclocking + | ^~ + t/t_clocking_bad5.v:29:20: ... Location of original declaration + 29 | global clocking ogck @(posedge clk); endclocking + | ^~~~ +%Error: t/t_clocking_bad5.v:32:20: Duplicate declaration of CLOCKING 'ck': 'ck' + 32 | global clocking ck @(posedge clk); endclocking + | ^~ + t/t_clocking_bad5.v:26:20: ... Location of original declaration + 26 | global clocking ck @(posedge clk); endclocking + | ^~ +%Error: t/t_clocking_bad5.v:16:14: Can't find definition of variable: '$global_clock' + 16 | always @ ($global_clock) $display; + | ^~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_clocking_bad5.pl b/test_regress/t/t_clocking_bad5.pl new file mode 100755 index 000000000..7fdfc93e0 --- /dev/null +++ b/test_regress/t/t_clocking_bad5.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + verilator_flags2 => ["--timing"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_clocking_bad5.v b/test_regress/t/t_clocking_bad5.v new file mode 100644 index 000000000..31eb33744 --- /dev/null +++ b/test_regress/t/t_clocking_bad5.v @@ -0,0 +1,34 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + sub sub(.*); + + // Bad - no global clock + always @ ($global_clock) $display; + +endmodule + +module sub(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + global clocking ck @(posedge clk); endclocking + + // Bad - global duplicate + global clocking ogck @(posedge clk); endclocking + + // Bad - name duplicate + global clocking ck @(posedge clk); endclocking + +endmodule diff --git a/test_regress/t/t_clocking_unsup1.out b/test_regress/t/t_clocking_unsup1.out index 1dce09ae4..164271f81 100644 --- a/test_regress/t/t_clocking_unsup1.out +++ b/test_regress/t/t_clocking_unsup1.out @@ -14,10 +14,4 @@ %Error-UNSUPPORTED: t/t_clocking_unsup1.v:18:15: Unsupported: clocking event edge override 18 | output edge #1 b; | ^~~~ -%Error-UNSUPPORTED: t/t_clocking_unsup1.v:13:20: Unsupported: global clocking - 13 | global clocking cb @(posedge clk); - | ^~ -%Error-UNSUPPORTED: t/t_clocking_unsup1.v:21:11: Unsupported: global clocking - 21 | global clocking @(posedge clk); - | ^~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_clocking_unsup1.v b/test_regress/t/t_clocking_unsup1.v index 0eac13dc7..7315e2e63 100644 --- a/test_regress/t/t_clocking_unsup1.v +++ b/test_regress/t/t_clocking_unsup1.v @@ -18,6 +18,4 @@ module t(/*AUTOARG*/ output edge #1 b; endclocking - global clocking @(posedge clk); - endclocking endmodule diff --git a/test_regress/t/t_comb_input_0.cpp b/test_regress/t/t_comb_input_0.cpp index 068210940..b08087648 100644 --- a/test_regress/t/t_comb_input_0.cpp +++ b/test_regress/t/t_comb_input_0.cpp @@ -22,7 +22,7 @@ int main(int argc, char** argv) { contextp->commandArgs(argc, argv); srand48(5); - const std::unique_ptr topp{new Vt_comb_input_0}; + const std::unique_ptr topp{new VM_PREFIX}; topp->inc = 1; topp->clk = false; topp->eval(); diff --git a/test_regress/t/t_comb_input_1.cpp b/test_regress/t/t_comb_input_1.cpp index b97948dad..62acf8373 100644 --- a/test_regress/t/t_comb_input_1.cpp +++ b/test_regress/t/t_comb_input_1.cpp @@ -22,7 +22,7 @@ int main(int argc, char** argv) { contextp->commandArgs(argc, argv); srand48(5); - const std::unique_ptr topp{new Vt_comb_input_1}; + const std::unique_ptr topp{new VM_PREFIX}; topp->inc = 1; topp->clk = false; topp->eval(); diff --git a/test_regress/t/t_comb_input_2.cpp b/test_regress/t/t_comb_input_2.cpp index 9d2aad472..0f3534650 100644 --- a/test_regress/t/t_comb_input_2.cpp +++ b/test_regress/t/t_comb_input_2.cpp @@ -22,7 +22,7 @@ int main(int argc, char** argv) { contextp->commandArgs(argc, argv); srand48(5); - const std::unique_ptr topp{new Vt_comb_input_2}; + const std::unique_ptr topp{new VM_PREFIX}; topp->inc = 1; topp->clk = false; topp->eval(); diff --git a/test_regress/t/t_concat_unpack.v b/test_regress/t/t_concat_unpack.v old mode 100755 new mode 100644 diff --git a/test_regress/t/t_const_bad.out b/test_regress/t/t_const_bad.out index 7aace9782..65358eb59 100644 --- a/test_regress/t/t_const_bad.out +++ b/test_regress/t/t_const_bad.out @@ -1,15 +1,15 @@ -%Warning-WIDTH: t/t_const_bad.v:13:39: Unsized constant being X/Z extended to 68 bits: ?32?bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - : ... In instance t +%Warning-WIDTHXZEXPAND: t/t_const_bad.v:13:39: Unsized constant being X/Z extended to 68 bits: ?32?bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + : ... In instance t 13 | if (68'hx_xxxxxxxx_xxxxxxxx !== 'dX) $stop; | ^~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. -%Warning-WIDTH: t/t_const_bad.v:14:39: Unsized constant being X/Z extended to 68 bits: ?32?bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz - : ... In instance t + ... For warning description see https://verilator.org/warn/WIDTHXZEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHXZEXPAND */" and lint_on around source to disable this message. +%Warning-WIDTHXZEXPAND: t/t_const_bad.v:14:39: Unsized constant being X/Z extended to 68 bits: ?32?bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz + : ... In instance t 14 | if (68'hz_zzzzzzzz_zzzzzzzz !== 'dZ) $stop; | ^~~ -%Warning-WIDTH: t/t_const_bad.v:15:39: Unsized constant being X/Z extended to 68 bits: ?32?bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz - : ... In instance t +%Warning-WIDTHXZEXPAND: t/t_const_bad.v:15:39: Unsized constant being X/Z extended to 68 bits: ?32?bzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz + : ... In instance t 15 | if (68'h?_????????_???????? !== 'd?) $stop; | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_const_bitoptree_bug3096.cpp b/test_regress/t/t_const_bitoptree_bug3096.cpp index deb9e1ee9..8c3dc8625 100644 --- a/test_regress/t/t_const_bitoptree_bug3096.cpp +++ b/test_regress/t/t_const_bitoptree_bug3096.cpp @@ -14,7 +14,7 @@ #include int main(int argc, char* argv[]) { - Vt_const_bitoptree_bug3096* const tb = new Vt_const_bitoptree_bug3096; + VM_PREFIX* const tb = new VM_PREFIX; tb->instr_i = 0x08c0006f; tb->eval(); diff --git a/test_regress/t/t_const_bitoptree_bug3096.pl b/test_regress/t/t_const_bitoptree_bug3096.pl index 16e215620..6a43c15a1 100755 --- a/test_regress/t/t_const_bitoptree_bug3096.pl +++ b/test_regress/t/t_const_bitoptree_bug3096.pl @@ -16,7 +16,9 @@ compile( v_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"], ); -execute(); +execute( + check_finished => 0, + ); ok(1); 1; diff --git a/test_regress/t/t_const_string_func.pl b/test_regress/t/t_const_string_func.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_const_string_func.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_const_string_func.v b/test_regress/t/t_const_string_func.v new file mode 100644 index 000000000..d410d7a27 --- /dev/null +++ b/test_regress/t/t_const_string_func.v @@ -0,0 +1,23 @@ +// DESCRIPTION: Verilator: constant string functions +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder +// SPDX-License-Identifier: CC0-1.0 + +module t (); + + function automatic string foo_func(); + foo_func = "FOO"; + foo_func = $sformatf("%sBAR", foo_func); + for (int i = 0; i < 4; i++) + foo_func = $sformatf("%s%0d", foo_func, i); + endfunction + + localparam string the_foo = foo_func(); + + initial begin + if (the_foo != "FOOBAR0123") $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_cover_line.out b/test_regress/t/t_cover_line.out index da95bcf79..dfb4ee40e 100644 --- a/test_regress/t/t_cover_line.out +++ b/test_regress/t/t_cover_line.out @@ -1,266 +1,360 @@ - // verilator_coverage annotation - // DESCRIPTION: Verilator: Verilog Test module - // - // This file ONLY is placed under the Creative Commons Public Domain, for - // any use, without warranty, 2008 by Wilson Snyder. - // SPDX-License-Identifier: CC0-1.0 - - module t (/*AUTOARG*/ - // Inputs - clk - ); - - input clk; - - reg toggle; -%000002 initial toggle=0; - - integer cyc; -%000002 initial cyc=1; - - wire [7:0] cyc_copy = cyc[7:0]; - - alpha a1 (/*AUTOINST*/ - // Inputs - .clk (clk), - .toggle (toggle)); - alpha a2 (/*AUTOINST*/ - // Inputs - .clk (clk), - .toggle (toggle)); - beta b1 (/*AUTOINST*/ - // Inputs - .clk (clk), - .toggle (toggle)); - beta b2 (/*AUTOINST*/ - // Inputs - .clk (clk), - .toggle (toggle)); - tsk t1 (/*AUTOINST*/ - // Inputs - .clk (clk), - .toggle (toggle)); - off o1 (/*AUTOINST*/ - // Inputs - .clk (clk), - .toggle (toggle)); - - 000020 always @ (posedge clk) begin - 000020 if (cyc!=0) begin -%000000 verilator_coverage: (next point on previous line) - - 000010 cyc <= cyc + 1; - 000010 toggle <= '0; - // Single and multiline if -%000002 if (cyc==3) $write(""); -%000009 verilator_coverage: (next point on previous line) - -%000002 if (cyc==3) -%000009 verilator_coverage: (next point on previous line) - -%000001 begin -%000001 $write(""); - end - // Single and multiline else -%000002 if (cyc==3) ; else $write(""); -%000018 verilator_coverage: (next point on previous line) - -%000002 if (cyc==3) ; -%000009 verilator_coverage: (next point on previous line) - - else -%000009 begin -%000009 $write(""); - end - // Single and multiline if else -%000002 if (cyc==3) $write(""); else $write(""); -%000018 verilator_coverage: (next point on previous line) - -%000002 if (cyc==3) -%000009 verilator_coverage: (next point on previous line) - -%000001 begin -%000001 $write(""); - end - else -%000009 begin -%000009 $write(""); - end - // multiline elseif -%000002 if (cyc==3) -%000001 begin -%000001 $write(""); - end -%000002 else if (cyc==4) -%000001 begin -%000001 $write(""); - end -%000002 else if (cyc==5) -%000007 verilator_coverage: (next point on previous line) - -%000001 begin -%000001 $write(""); - end - else -%000007 begin -%000007 $write(""); - end - // Single and multiline while -%000000 while (0); -%000000 while (0) begin -%000000 $write(""); - end -%000000 do ; while (0); - 000010 do begin -%000000 verilator_coverage: (next point on previous line) - - 000010 $write(""); -%000000 verilator_coverage: (next point on previous line) - -%000000 end while (0); - //=== - // Task and complicated -%000002 if (cyc==3) begin -%000001 toggle <= '1; - end -%000002 else if (cyc==5) begin - `ifdef VERILATOR -%000001 $c("this->call_task();"); - `else - call_task(); - `endif - end -%000002 else if (cyc==10) begin -%000007 verilator_coverage: (next point on previous line) - -%000001 $write("*-* All Finished *-*\n"); -%000001 $finish; - end - end - end - -%000002 task call_task; - /* verilator public */ -%000001 t1.center_task(1'b1); - endtask - - endmodule - - module alpha (/*AUTOARG*/ - // Inputs - clk, toggle - ); - input clk; - input toggle; - 000040 always @ (posedge clk) begin -%000004 if (toggle) begin // CHECK_COVER(0,"top.t.a*",2) - 000018 verilator_coverage: (next point on previous line) - -%000002 $write(""); - // t.a1 and t.a2 collapse to a count of 2 - end - 000018 if (toggle) begin - $write(""); // CHECK_COVER_MISSING(0) - // This doesn't even get added - `ifdef ATTRIBUTE - // verilator coverage_block_off - `endif - end - end - endmodule - - module beta (/*AUTOARG*/ - // Inputs - clk, toggle - ); - input clk; - input toggle; - - /* verilator public_module */ - - 000040 always @ (posedge clk) begin - 000020 $write(""); // Always covered -%000000 if (0) begin // CHECK_COVER(0,"top.t.b*",0) - 000020 verilator_coverage: (next point on previous line) - - // Make sure that we don't optimize away zero buckets -%000000 $write(""); - end -%000004 if (toggle) begin // CHECK_COVER(0,"top.t.b*",2) - 000018 verilator_coverage: (next point on previous line) - - // t.b1 and t.b2 collapse to a count of 2 -%000002 $write(""); - end - 000018 if (toggle) begin : block - // This doesn't - `ifdef ATTRIBUTE - // verilator coverage_block_off - `endif - begin end // Needed for .vlt to attach coverage_block_off - if (1) begin end // CHECK_COVER_MISSING(0) - $write(""); // CHECK_COVER_MISSING(0) - end - end - endmodule - - module tsk (/*AUTOARG*/ - // Inputs - clk, toggle - ); - input clk; - input toggle; - - /* verilator public_module */ - - 000020 always @ (posedge clk) begin - 000010 center_task(1'b0); - end - - 000022 task center_task; - input external; - 000011 begin -%000002 if (toggle) begin // CHECK_COVER(0,"top.t.t1",1) - 000010 verilator_coverage: (next point on previous line) - -%000001 $write(""); - end -%000002 if (external) begin // CHECK_COVER(0,"top.t.t1",1) - 000010 verilator_coverage: (next point on previous line) - -%000001 $write("[%0t] Got external pulse\n", $time); - end - end - endtask - - endmodule - - module off (/*AUTOARG*/ - // Inputs - clk, toggle - ); - input clk; - input toggle; - - // verilator coverage_off - always @ (posedge clk) begin - if (toggle) begin - $write(""); // CHECK_COVER_MISSING(0) - // because under coverage_module_off - end - end - // verilator coverage_on - 000020 always @ (posedge clk) begin -%000002 if (toggle) begin -%000009 verilator_coverage: (next point on previous line) - - // because under coverage_module_off -%000001 $write(""); -%000000 if (0) ; // CHECK_COVER(0,"top.t.o1",1) -%000001 verilator_coverage: (next point on previous line) - - end - end - - endmodule - +// // verilator_coverage annotation + // DESCRIPTION: Verilator: Verilog Test module + // + // This file ONLY is placed under the Creative Commons Public Domain, for + // any use, without warranty, 2008 by Wilson Snyder. + // SPDX-License-Identifier: CC0-1.0 + + module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + reg toggle; +%000001 initial toggle=0; +-000001 point: comment=block + + integer cyc; +%000001 initial cyc=1; +-000001 point: comment=block + + wire [7:0] cyc_copy = cyc[7:0]; + + alpha a1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + alpha a2 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + beta b1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + beta b2 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + tsk t1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + off o1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + + 000010 always @ (posedge clk) begin ++000010 point: comment=block +%000000 if (cyc!=0) begin ++000010 point: comment=if +-000000 point: comment=else + 000010 cyc <= cyc + 1; ++000010 point: comment=if + 000010 toggle <= '0; ++000010 point: comment=if + // Single and multiline if +%000001 if (cyc==3) $write(""); +-000001 point: comment=if +-000009 point: comment=else +%000001 if (cyc==3) +-000001 point: comment=if +-000009 point: comment=else +%000001 begin +-000001 point: comment=if +%000001 $write(""); +-000001 point: comment=if + end + // Single and multiline else +%000001 if (cyc==3) ; else $write(""); +-000001 point: comment=if +-000009 point: comment=else +%000001 if (cyc==3) ; +-000001 point: comment=if +-000009 point: comment=else + else +%000009 begin +-000009 point: comment=else +%000009 $write(""); +-000009 point: comment=else + end + // Single and multiline if else +%000001 if (cyc==3) $write(""); else $write(""); +-000001 point: comment=if +-000009 point: comment=else +%000001 if (cyc==3) +-000001 point: comment=if +-000009 point: comment=else +%000001 begin +-000001 point: comment=if +%000001 $write(""); +-000001 point: comment=if + end + else +%000009 begin +-000009 point: comment=else +%000009 $write(""); +-000009 point: comment=else + end + // multiline elseif +%000001 if (cyc==3) +-000001 point: comment=elsif +%000001 begin +-000001 point: comment=elsif +%000001 $write(""); +-000001 point: comment=elsif + end +%000001 else if (cyc==4) +-000001 point: comment=elsif +%000001 begin +-000001 point: comment=elsif +%000001 $write(""); +-000001 point: comment=elsif + end +%000001 else if (cyc==5) +-000001 point: comment=if +-000007 point: comment=else +%000001 begin +-000001 point: comment=if +%000001 $write(""); +-000001 point: comment=if + end + else +%000007 begin +-000007 point: comment=else +%000007 $write(""); +-000007 point: comment=else + end + // Single and multiline while +%000000 while (0); +-000000 point: comment=block +%000000 while (0) begin +-000000 point: comment=block +%000000 $write(""); +-000000 point: comment=block + end +%000000 do ; while (0); +-000000 point: comment=block +%000000 do begin ++000010 point: comment=if +-000000 point: comment=block +%000000 $write(""); ++000010 point: comment=if +-000000 point: comment=block +%000000 end while (0); +-000000 point: comment=block + //=== + // Task and complicated +%000001 if (cyc==3) begin +-000001 point: comment=elsif +%000001 toggle <= '1; +-000001 point: comment=elsif + end +%000001 else if (cyc==5) begin +-000001 point: comment=elsif + `ifdef VERILATOR +%000001 $c("this->call_task();"); +-000001 point: comment=elsif + `else + call_task(); + `endif + end +%000001 else if (cyc==10) begin +-000001 point: comment=if +-000007 point: comment=else +%000001 $write("*-* All Finished *-*\n"); +-000001 point: comment=if +%000001 $finish; +-000001 point: comment=if + end + end + end + +%000001 task call_task; +-000001 point: comment=block + /* verilator public */ +%000001 t1.center_task(1'b1); +-000001 point: comment=block + endtask + + endmodule + + module alpha (/*AUTOARG*/ + // Inputs + clk, toggle + ); + input clk; + input toggle; + 000020 always @ (posedge clk) begin ++000020 point: comment=block +%000002 if (toggle) begin // CHECK_COVER(0,"top.t.a*",2) +-000002 point: comment=if ++000018 point: comment=else +%000002 $write(""); +-000002 point: comment=if + // t.a1 and t.a2 collapse to a count of 2 + end + 000018 if (toggle) begin ++000018 point: comment=else + $write(""); // CHECK_COVER_MISSING(0) + // This doesn't even get added + `ifdef ATTRIBUTE + // verilator coverage_block_off + `endif + end + end + endmodule + + module beta (/*AUTOARG*/ + // Inputs + clk, toggle + ); + input clk; + input toggle; + + /* verilator public_module */ + + 000020 always @ (posedge clk) begin ++000020 point: comment=block + 000020 $write(""); // Always covered ++000020 point: comment=block + 000020 if (0) begin // CHECK_COVER(0,"top.t.b*",0) +-000000 point: comment=if ++000020 point: comment=else + // Make sure that we don't optimize away zero buckets +%000000 $write(""); +-000000 point: comment=if + end +%000002 if (toggle) begin // CHECK_COVER(0,"top.t.b*",2) +-000002 point: comment=if ++000018 point: comment=else + // t.b1 and t.b2 collapse to a count of 2 +%000002 $write(""); +-000002 point: comment=if + end + 000018 if (toggle) begin : block ++000018 point: comment=else + // This doesn't + `ifdef ATTRIBUTE + // verilator coverage_block_off + `endif + begin end // Needed for .vlt to attach coverage_block_off + if (1) begin end // CHECK_COVER_MISSING(0) + $write(""); // CHECK_COVER_MISSING(0) + end + end + endmodule + + class Cls; + bit m_toggle; +%000001 function new(bit toggle); +-000001 point: comment=block +%000001 m_toggle = toggle; +-000001 point: comment=block +%000000 if (m_toggle) begin // CHECK_COVER(0,"top.$unit::Cls",1) +-000001 point: comment=if +-000000 point: comment=else +%000001 $write(""); +-000001 point: comment=if + end + endfunction + 000011 static function void fstatic(bit toggle); ++000011 point: comment=block +%000000 if (1) begin // CHECK_COVER(0,"top.$unit::Cls",1) ++000011 point: comment=if +-000000 point: comment=else + 000011 $write(""); ++000011 point: comment=if + end + endfunction + 000011 function void fauto(); ++000011 point: comment=block +%000000 if (m_toggle) begin // CHECK_COVER(0,"top.$unit::Cls",1) ++000011 point: comment=if +-000000 point: comment=else + 000011 $write(""); ++000011 point: comment=if + end + endfunction + endclass + + module tsk (/*AUTOARG*/ + // Inputs + clk, toggle + ); + input clk; + input toggle; + + /* verilator public_module */ + + 000010 always @ (posedge clk) begin ++000010 point: comment=block + 000010 center_task(1'b0); ++000010 point: comment=block + end + + 000011 task center_task; ++000011 point: comment=block + input external; + 000011 begin ++000011 point: comment=block +%000001 if (toggle) begin // CHECK_COVER(0,"top.t.t1",1) +-000001 point: comment=if ++000010 point: comment=else +%000001 $write(""); +-000001 point: comment=if + end +%000001 if (external) begin // CHECK_COVER(0,"top.t.t1",1) +-000001 point: comment=if ++000010 point: comment=else +%000001 $write("[%0t] Got external pulse\n", $time); +-000001 point: comment=if + end + end + 000011 begin ++000011 point: comment=block +%000001 Cls c = new(1'b1); +-000001 point: comment=block + 000011 c.fauto(); ++000011 point: comment=block + 000011 Cls::fstatic(1'b1); ++000011 point: comment=block + end + endtask + + endmodule + + module off (/*AUTOARG*/ + // Inputs + clk, toggle + ); + input clk; + input toggle; + + // verilator coverage_off + always @ (posedge clk) begin + if (toggle) begin + $write(""); // CHECK_COVER_MISSING(0) + // because under coverage_module_off + end + end + // verilator coverage_on + 000010 always @ (posedge clk) begin ++000010 point: comment=block +%000001 if (toggle) begin +-000001 point: comment=if +-000009 point: comment=else + // because under coverage_module_off +%000001 $write(""); +-000001 point: comment=if +%000001 if (0) ; // CHECK_COVER(0,"top.t.o1",1) +-000000 point: comment=if +-000001 point: comment=else + end + end + + endmodule + diff --git a/test_regress/t/t_cover_line.v b/test_regress/t/t_cover_line.v index 6b03de5e7..49da71cdc 100644 --- a/test_regress/t/t_cover_line.v +++ b/test_regress/t/t_cover_line.v @@ -175,6 +175,26 @@ module beta (/*AUTOARG*/ end endmodule +class Cls; + bit m_toggle; + function new(bit toggle); + m_toggle = toggle; + if (m_toggle) begin // CHECK_COVER(0,"top.$unit::Cls",1) + $write(""); + end + endfunction + static function void fstatic(bit toggle); + if (1) begin // CHECK_COVER(0,"top.$unit::Cls",1) + $write(""); + end + endfunction + function void fauto(); + if (m_toggle) begin // CHECK_COVER(0,"top.$unit::Cls",1) + $write(""); + end + endfunction +endclass + module tsk (/*AUTOARG*/ // Inputs clk, toggle @@ -198,6 +218,11 @@ module tsk (/*AUTOARG*/ $write("[%0t] Got external pulse\n", $time); end end + begin + Cls c = new(1'b1); + c.fauto(); + Cls::fstatic(1'b1); + end endtask endmodule diff --git a/test_regress/t/t_cover_line_cc.pl b/test_regress/t/t_cover_line_cc.pl index 8c8d785ae..60efcb2da 100755 --- a/test_regress/t/t_cover_line_cc.pl +++ b/test_regress/t/t_cover_line_cc.pl @@ -25,6 +25,7 @@ execute( inline_checks(); run(cmd => ["../bin/verilator_coverage", + "--annotate-points", "--annotate", "$Self->{obj_dir}/annotated", "$Self->{obj_dir}/coverage.dat"], verilator_run => 1, diff --git a/test_regress/t/t_cover_line_cc_vlt.pl b/test_regress/t/t_cover_line_cc_vlt.pl index 6b885fb8f..dac2c2e24 100755 --- a/test_regress/t/t_cover_line_cc_vlt.pl +++ b/test_regress/t/t_cover_line_cc_vlt.pl @@ -25,6 +25,7 @@ execute( inline_checks(); run(cmd => ["../bin/verilator_coverage", + "--annotate-points", "--annotate", "$Self->{obj_dir}/annotated", "$Self->{obj_dir}/coverage.dat", ], diff --git a/test_regress/t/t_cover_line_trace.out b/test_regress/t/t_cover_line_trace.out index 9c6365e91..e32c0cd15 100644 --- a/test_regress/t/t_cover_line_trace.out +++ b/test_regress/t/t_cover_line_trace.out @@ -1,98 +1,98 @@ $version Generated by VerilatedVcd $end -$date Sat Dec 18 13:32:31 2021 $end $timescale 1ps $end $scope module top $end - $var wire 1 W clk $end + $var wire 1 X clk $end $scope module t $end - $var wire 1 W clk $end - $var wire 32 & cyc [31:0] $end - $var wire 8 ' cyc_copy [7:0] $end - $var wire 1 % toggle $end - $var wire 32 ; vlCoverageLineTrace_t_cover_line__102_elsif [31:0] $end - $var wire 32 < vlCoverageLineTrace_t_cover_line__105_elsif [31:0] $end - $var wire 32 = vlCoverageLineTrace_t_cover_line__112_else [31:0] $end - $var wire 32 > vlCoverageLineTrace_t_cover_line__112_if [31:0] $end - $var wire 32 X vlCoverageLineTrace_t_cover_line__119_block [31:0] $end + $var wire 1 X clk $end + $var wire 32 ' cyc [31:0] $end + $var wire 8 ( cyc_copy [7:0] $end + $var wire 1 & toggle $end + $var wire 32 < vlCoverageLineTrace_t_cover_line__102_elsif [31:0] $end + $var wire 32 = vlCoverageLineTrace_t_cover_line__105_elsif [31:0] $end + $var wire 32 > vlCoverageLineTrace_t_cover_line__112_else [31:0] $end + $var wire 32 ? vlCoverageLineTrace_t_cover_line__112_if [31:0] $end + $var wire 32 Y vlCoverageLineTrace_t_cover_line__119_block [31:0] $end $var wire 32 # vlCoverageLineTrace_t_cover_line__15_block [31:0] $end $var wire 32 $ vlCoverageLineTrace_t_cover_line__18_block [31:0] $end - $var wire 32 ( vlCoverageLineTrace_t_cover_line__47_block [31:0] $end - $var wire 32 ) vlCoverageLineTrace_t_cover_line__48_else [31:0] $end - $var wire 32 * vlCoverageLineTrace_t_cover_line__48_if [31:0] $end - $var wire 32 + vlCoverageLineTrace_t_cover_line__52_else [31:0] $end - $var wire 32 , vlCoverageLineTrace_t_cover_line__52_if [31:0] $end - $var wire 32 - vlCoverageLineTrace_t_cover_line__53_else [31:0] $end - $var wire 32 . vlCoverageLineTrace_t_cover_line__53_if [31:0] $end - $var wire 32 / vlCoverageLineTrace_t_cover_line__58_else [31:0] $end - $var wire 32 0 vlCoverageLineTrace_t_cover_line__58_if [31:0] $end - $var wire 32 1 vlCoverageLineTrace_t_cover_line__59_else [31:0] $end - $var wire 32 2 vlCoverageLineTrace_t_cover_line__59_if [31:0] $end - $var wire 32 3 vlCoverageLineTrace_t_cover_line__65_else [31:0] $end - $var wire 32 4 vlCoverageLineTrace_t_cover_line__65_if [31:0] $end - $var wire 32 5 vlCoverageLineTrace_t_cover_line__66_else [31:0] $end - $var wire 32 6 vlCoverageLineTrace_t_cover_line__66_if [31:0] $end - $var wire 32 7 vlCoverageLineTrace_t_cover_line__75_elsif [31:0] $end - $var wire 32 8 vlCoverageLineTrace_t_cover_line__79_elsif [31:0] $end - $var wire 32 9 vlCoverageLineTrace_t_cover_line__83_else [31:0] $end - $var wire 32 : vlCoverageLineTrace_t_cover_line__83_if [31:0] $end - $var wire 32 ] vlCoverageLineTrace_t_cover_line__92_block [31:0] $end - $var wire 32 ^ vlCoverageLineTrace_t_cover_line__93_block [31:0] $end - $var wire 32 _ vlCoverageLineTrace_t_cover_line__96_block [31:0] $end - $var wire 32 ` vlCoverageLineTrace_t_cover_line__97_block [31:0] $end + $var wire 32 ) vlCoverageLineTrace_t_cover_line__47_block [31:0] $end + $var wire 32 * vlCoverageLineTrace_t_cover_line__48_else [31:0] $end + $var wire 32 + vlCoverageLineTrace_t_cover_line__48_if [31:0] $end + $var wire 32 , vlCoverageLineTrace_t_cover_line__52_else [31:0] $end + $var wire 32 - vlCoverageLineTrace_t_cover_line__52_if [31:0] $end + $var wire 32 . vlCoverageLineTrace_t_cover_line__53_else [31:0] $end + $var wire 32 / vlCoverageLineTrace_t_cover_line__53_if [31:0] $end + $var wire 32 0 vlCoverageLineTrace_t_cover_line__58_else [31:0] $end + $var wire 32 1 vlCoverageLineTrace_t_cover_line__58_if [31:0] $end + $var wire 32 2 vlCoverageLineTrace_t_cover_line__59_else [31:0] $end + $var wire 32 3 vlCoverageLineTrace_t_cover_line__59_if [31:0] $end + $var wire 32 4 vlCoverageLineTrace_t_cover_line__65_else [31:0] $end + $var wire 32 5 vlCoverageLineTrace_t_cover_line__65_if [31:0] $end + $var wire 32 6 vlCoverageLineTrace_t_cover_line__66_else [31:0] $end + $var wire 32 7 vlCoverageLineTrace_t_cover_line__66_if [31:0] $end + $var wire 32 8 vlCoverageLineTrace_t_cover_line__75_elsif [31:0] $end + $var wire 32 9 vlCoverageLineTrace_t_cover_line__79_elsif [31:0] $end + $var wire 32 : vlCoverageLineTrace_t_cover_line__83_else [31:0] $end + $var wire 32 ; vlCoverageLineTrace_t_cover_line__83_if [31:0] $end + $var wire 32 ^ vlCoverageLineTrace_t_cover_line__92_block [31:0] $end + $var wire 32 _ vlCoverageLineTrace_t_cover_line__93_block [31:0] $end + $var wire 32 ` vlCoverageLineTrace_t_cover_line__96_block [31:0] $end + $var wire 32 a vlCoverageLineTrace_t_cover_line__97_block [31:0] $end $scope module a1 $end - $var wire 1 W clk $end - $var wire 1 % toggle $end - $var wire 32 ? vlCoverageLineTrace_t_cover_line__132_block [31:0] $end - $var wire 32 @ vlCoverageLineTrace_t_cover_line__133_else [31:0] $end - $var wire 32 A vlCoverageLineTrace_t_cover_line__133_if [31:0] $end - $var wire 32 B vlCoverageLineTrace_t_cover_line__137_else [31:0] $end + $var wire 1 X clk $end + $var wire 1 & toggle $end + $var wire 32 @ vlCoverageLineTrace_t_cover_line__132_block [31:0] $end + $var wire 32 A vlCoverageLineTrace_t_cover_line__133_else [31:0] $end + $var wire 32 B vlCoverageLineTrace_t_cover_line__133_if [31:0] $end + $var wire 32 C vlCoverageLineTrace_t_cover_line__137_else [31:0] $end $upscope $end $scope module a2 $end - $var wire 1 W clk $end - $var wire 1 % toggle $end - $var wire 32 C vlCoverageLineTrace_t_cover_line__132_block [31:0] $end - $var wire 32 D vlCoverageLineTrace_t_cover_line__133_else [31:0] $end - $var wire 32 E vlCoverageLineTrace_t_cover_line__133_if [31:0] $end - $var wire 32 F vlCoverageLineTrace_t_cover_line__137_else [31:0] $end + $var wire 1 X clk $end + $var wire 1 & toggle $end + $var wire 32 D vlCoverageLineTrace_t_cover_line__132_block [31:0] $end + $var wire 32 E vlCoverageLineTrace_t_cover_line__133_else [31:0] $end + $var wire 32 F vlCoverageLineTrace_t_cover_line__133_if [31:0] $end + $var wire 32 G vlCoverageLineTrace_t_cover_line__137_else [31:0] $end $upscope $end $scope module b1 $end - $var wire 1 W clk $end - $var wire 1 % toggle $end - $var wire 32 K vlCoverageLineTrace_t_cover_line__156_block [31:0] $end - $var wire 32 L vlCoverageLineTrace_t_cover_line__158_else [31:0] $end - $var wire 32 b vlCoverageLineTrace_t_cover_line__158_if [31:0] $end - $var wire 32 M vlCoverageLineTrace_t_cover_line__162_else [31:0] $end - $var wire 32 N vlCoverageLineTrace_t_cover_line__162_if [31:0] $end - $var wire 32 O vlCoverageLineTrace_t_cover_line__166_else [31:0] $end + $var wire 1 X clk $end + $var wire 1 & toggle $end + $var wire 32 L vlCoverageLineTrace_t_cover_line__156_block [31:0] $end + $var wire 32 M vlCoverageLineTrace_t_cover_line__158_else [31:0] $end + $var wire 32 c vlCoverageLineTrace_t_cover_line__158_if [31:0] $end + $var wire 32 N vlCoverageLineTrace_t_cover_line__162_else [31:0] $end + $var wire 32 O vlCoverageLineTrace_t_cover_line__162_if [31:0] $end + $var wire 32 P vlCoverageLineTrace_t_cover_line__166_else [31:0] $end $upscope $end $scope module b2 $end - $var wire 1 W clk $end - $var wire 1 % toggle $end - $var wire 32 P vlCoverageLineTrace_t_cover_line__156_block [31:0] $end - $var wire 32 Q vlCoverageLineTrace_t_cover_line__158_else [31:0] $end - $var wire 32 c vlCoverageLineTrace_t_cover_line__158_if [31:0] $end - $var wire 32 R vlCoverageLineTrace_t_cover_line__162_else [31:0] $end - $var wire 32 S vlCoverageLineTrace_t_cover_line__162_if [31:0] $end - $var wire 32 T vlCoverageLineTrace_t_cover_line__166_else [31:0] $end + $var wire 1 X clk $end + $var wire 1 & toggle $end + $var wire 32 Q vlCoverageLineTrace_t_cover_line__156_block [31:0] $end + $var wire 32 R vlCoverageLineTrace_t_cover_line__158_else [31:0] $end + $var wire 32 d vlCoverageLineTrace_t_cover_line__158_if [31:0] $end + $var wire 32 S vlCoverageLineTrace_t_cover_line__162_else [31:0] $end + $var wire 32 T vlCoverageLineTrace_t_cover_line__162_if [31:0] $end + $var wire 32 U vlCoverageLineTrace_t_cover_line__166_else [31:0] $end $upscope $end $scope module o1 $end - $var wire 1 W clk $end - $var wire 1 % toggle $end - $var wire 32 G vlCoverageLineTrace_t_cover_line__220_block [31:0] $end - $var wire 32 H vlCoverageLineTrace_t_cover_line__221_else [31:0] $end - $var wire 32 I vlCoverageLineTrace_t_cover_line__221_if [31:0] $end - $var wire 32 J vlCoverageLineTrace_t_cover_line__224_else [31:0] $end - $var wire 32 a vlCoverageLineTrace_t_cover_line__224_if [31:0] $end + $var wire 1 X clk $end + $var wire 1 & toggle $end + $var wire 32 H vlCoverageLineTrace_t_cover_line__245_block [31:0] $end + $var wire 32 I vlCoverageLineTrace_t_cover_line__246_else [31:0] $end + $var wire 32 J vlCoverageLineTrace_t_cover_line__246_if [31:0] $end + $var wire 32 K vlCoverageLineTrace_t_cover_line__249_else [31:0] $end + $var wire 32 b vlCoverageLineTrace_t_cover_line__249_if [31:0] $end $upscope $end $scope module t1 $end - $var wire 1 W clk $end - $var wire 1 % toggle $end - $var wire 32 U vlCoverageLineTrace_t_cover_line__187_block [31:0] $end - $var wire 32 Y vlCoverageLineTrace_t_cover_line__191_block [31:0] $end - $var wire 32 Z vlCoverageLineTrace_t_cover_line__194_else [31:0] $end - $var wire 32 [ vlCoverageLineTrace_t_cover_line__194_if [31:0] $end - $var wire 32 V vlCoverageLineTrace_t_cover_line__197_else [31:0] $end - $var wire 32 \ vlCoverageLineTrace_t_cover_line__197_if [31:0] $end + $var wire 1 X clk $end + $var wire 1 & toggle $end + $var wire 32 V vlCoverageLineTrace_t_cover_line__207_block [31:0] $end + $var wire 32 Z vlCoverageLineTrace_t_cover_line__211_block [31:0] $end + $var wire 32 [ vlCoverageLineTrace_t_cover_line__214_else [31:0] $end + $var wire 32 \ vlCoverageLineTrace_t_cover_line__214_if [31:0] $end + $var wire 32 W vlCoverageLineTrace_t_cover_line__217_else [31:0] $end + $var wire 32 ] vlCoverageLineTrace_t_cover_line__217_if [31:0] $end + $var wire 32 % vlCoverageLineTrace_t_cover_line__222_block [31:0] $end $upscope $end $upscope $end $upscope $end @@ -102,10 +102,10 @@ $enddefinitions $end #0 b00000000000000000000000000000001 # b00000000000000000000000000000001 $ -0% -b00000000000000000000000000000001 & -b00000001 ' -b00000000000000000000000000000000 ( +b00000000000000000000000000000001 % +0& +b00000000000000000000000000000001 ' +b00000001 ( b00000000000000000000000000000000 ) b00000000000000000000000000000000 * b00000000000000000000000000000000 + @@ -152,8 +152,8 @@ b00000000000000000000000000000000 S b00000000000000000000000000000000 T b00000000000000000000000000000000 U b00000000000000000000000000000000 V -0W -b00000000000000000000000000000000 X +b00000000000000000000000000000000 W +0X b00000000000000000000000000000000 Y b00000000000000000000000000000000 Z b00000000000000000000000000000000 [ @@ -165,362 +165,363 @@ b00000000000000000000000000000000 ` b00000000000000000000000000000000 a b00000000000000000000000000000000 b b00000000000000000000000000000000 c +b00000000000000000000000000000000 d #10 -b00000000000000000000000000000010 & -b00000010 ' -b00000000000000000000000000000001 ( -b00000000000000000000000000000001 * +b00000000000000000000000000000010 ' +b00000010 ( +b00000000000000000000000000000001 ) b00000000000000000000000000000001 + -b00000000000000000000000000000001 - -b00000000000000000000000000000001 / -b00000000000000000000000000000001 1 -b00000000000000000000000000000001 3 -b00000000000000000000000000000001 5 -b00000000000000000000000000000001 9 -b00000000000000000000000000000001 = -b00000000000000000000000000000001 ? -b00000000000000000000000000000001 @ -b00000000000000000000000000000001 B -b00000000000000000000000000000001 C -b00000000000000000000000000000001 D -b00000000000000000000000000000001 F -b00000000000000000000000000000001 G -b00000000000000000000000000000001 H -b00000000000000000000000000000001 K -b00000000000000000000000000000001 L -b00000000000000000000000000000001 M -b00000000000000000000000000000001 O -b00000000000000000000000000000001 P -b00000000000000000000000000000001 Q -b00000000000000000000000000000001 R -b00000000000000000000000000000001 T -b00000000000000000000000000000001 U -b00000000000000000000000000000001 V -1W -b00000000000000000000000000000001 Y -b00000000000000000000000000000001 Z -#15 -0W -#20 -b00000000000000000000000000000011 & -b00000011 ' -b00000000000000000000000000000010 ( -b00000000000000000000000000000010 * -b00000000000000000000000000000010 + -b00000000000000000000000000000010 - -b00000000000000000000000000000010 / -b00000000000000000000000000000010 1 -b00000000000000000000000000000010 3 -b00000000000000000000000000000010 5 -b00000000000000000000000000000010 9 -b00000000000000000000000000000010 = -b00000000000000000000000000000010 ? -b00000000000000000000000000000010 @ -b00000000000000000000000000000010 B -b00000000000000000000000000000010 C -b00000000000000000000000000000010 D -b00000000000000000000000000000010 F -b00000000000000000000000000000010 G -b00000000000000000000000000000010 H -b00000000000000000000000000000010 K -b00000000000000000000000000000010 L -b00000000000000000000000000000010 M -b00000000000000000000000000000010 O -b00000000000000000000000000000010 P -b00000000000000000000000000000010 Q -b00000000000000000000000000000010 R -b00000000000000000000000000000010 T -b00000000000000000000000000000010 U -b00000000000000000000000000000010 V -1W -b00000000000000000000000000000010 Y -b00000000000000000000000000000010 Z -#25 -0W -#30 -1% -b00000000000000000000000000000100 & -b00000100 ' -b00000000000000000000000000000011 ( -b00000000000000000000000000000011 * b00000000000000000000000000000001 , b00000000000000000000000000000001 . b00000000000000000000000000000001 0 b00000000000000000000000000000001 2 b00000000000000000000000000000001 4 b00000000000000000000000000000001 6 +b00000000000000000000000000000001 : +b00000000000000000000000000000001 > +b00000000000000000000000000000001 @ +b00000000000000000000000000000001 A +b00000000000000000000000000000001 C +b00000000000000000000000000000001 D +b00000000000000000000000000000001 E +b00000000000000000000000000000001 G +b00000000000000000000000000000001 H +b00000000000000000000000000000001 I +b00000000000000000000000000000001 L +b00000000000000000000000000000001 M +b00000000000000000000000000000001 N +b00000000000000000000000000000001 P +b00000000000000000000000000000001 Q +b00000000000000000000000000000001 R +b00000000000000000000000000000001 S +b00000000000000000000000000000001 U +b00000000000000000000000000000001 V +b00000000000000000000000000000001 W +1X +b00000000000000000000000000000001 Z +b00000000000000000000000000000001 [ +#15 +0X +#20 +b00000000000000000000000000000011 ' +b00000011 ( +b00000000000000000000000000000010 ) +b00000000000000000000000000000010 + +b00000000000000000000000000000010 , +b00000000000000000000000000000010 . +b00000000000000000000000000000010 0 +b00000000000000000000000000000010 2 +b00000000000000000000000000000010 4 +b00000000000000000000000000000010 6 +b00000000000000000000000000000010 : +b00000000000000000000000000000010 > +b00000000000000000000000000000010 @ +b00000000000000000000000000000010 A +b00000000000000000000000000000010 C +b00000000000000000000000000000010 D +b00000000000000000000000000000010 E +b00000000000000000000000000000010 G +b00000000000000000000000000000010 H +b00000000000000000000000000000010 I +b00000000000000000000000000000010 L +b00000000000000000000000000000010 M +b00000000000000000000000000000010 N +b00000000000000000000000000000010 P +b00000000000000000000000000000010 Q +b00000000000000000000000000000010 R +b00000000000000000000000000000010 S +b00000000000000000000000000000010 U +b00000000000000000000000000000010 V +b00000000000000000000000000000010 W +1X +b00000000000000000000000000000010 Z +b00000000000000000000000000000010 [ +#25 +0X +#30 +1& +b00000000000000000000000000000100 ' +b00000100 ( +b00000000000000000000000000000011 ) +b00000000000000000000000000000011 + +b00000000000000000000000000000001 - +b00000000000000000000000000000001 / +b00000000000000000000000000000001 1 +b00000000000000000000000000000001 3 +b00000000000000000000000000000001 5 b00000000000000000000000000000001 7 -b00000000000000000000000000000001 ; -b00000000000000000000000000000011 ? +b00000000000000000000000000000001 8 +b00000000000000000000000000000001 < b00000000000000000000000000000011 @ -b00000000000000000000000000000011 B +b00000000000000000000000000000011 A b00000000000000000000000000000011 C b00000000000000000000000000000011 D -b00000000000000000000000000000011 F +b00000000000000000000000000000011 E b00000000000000000000000000000011 G b00000000000000000000000000000011 H -b00000000000000000000000000000011 K +b00000000000000000000000000000011 I b00000000000000000000000000000011 L b00000000000000000000000000000011 M -b00000000000000000000000000000011 O +b00000000000000000000000000000011 N b00000000000000000000000000000011 P b00000000000000000000000000000011 Q b00000000000000000000000000000011 R -b00000000000000000000000000000011 T +b00000000000000000000000000000011 S b00000000000000000000000000000011 U b00000000000000000000000000000011 V -1W -b00000000000000000000000000000011 Y +b00000000000000000000000000000011 W +1X b00000000000000000000000000000011 Z +b00000000000000000000000000000011 [ #35 -0W +0X #40 -0% -b00000000000000000000000000000101 & -b00000101 ' -b00000000000000000000000000000100 ( -b00000000000000000000000000000100 * -b00000000000000000000000000000011 + -b00000000000000000000000000000011 - -b00000000000000000000000000000011 / -b00000000000000000000000000000011 1 -b00000000000000000000000000000011 3 -b00000000000000000000000000000011 5 -b00000000000000000000000000000001 8 -b00000000000000000000000000000011 = -b00000000000000000000000000000100 ? -b00000000000000000000000000000001 A -b00000000000000000000000000000100 C -b00000000000000000000000000000001 E -b00000000000000000000000000000100 G -b00000000000000000000000000000001 I -b00000000000000000000000000000001 J -b00000000000000000000000000000100 K -b00000000000000000000000000000100 L -b00000000000000000000000000000001 N -b00000000000000000000000000000100 P -b00000000000000000000000000000100 Q -b00000000000000000000000000000001 S -b00000000000000000000000000000100 U -b00000000000000000000000000000100 V -1W -b00000000000000000000000000000100 Y -b00000000000000000000000000000001 [ -#45 -0W -#50 -b00000000000000000000000000000110 & -b00000110 ' -b00000000000000000000000000000101 ( -b00000000000000000000000000000101 * +0& +b00000000000000000000000000000101 ' +b00000101 ( +b00000000000000000000000000000100 ) b00000000000000000000000000000100 + -b00000000000000000000000000000100 - -b00000000000000000000000000000100 / -b00000000000000000000000000000100 1 -b00000000000000000000000000000100 3 -b00000000000000000000000000000100 5 -b00000000000000000000000000000001 : -b00000000000000000000000000000001 < -b00000000000000000000000000000101 ? +b00000000000000000000000000000011 , +b00000000000000000000000000000011 . +b00000000000000000000000000000011 0 +b00000000000000000000000000000011 2 +b00000000000000000000000000000011 4 +b00000000000000000000000000000011 6 +b00000000000000000000000000000001 9 +b00000000000000000000000000000011 > b00000000000000000000000000000100 @ -b00000000000000000000000000000100 B -b00000000000000000000000000000101 C +b00000000000000000000000000000001 B b00000000000000000000000000000100 D -b00000000000000000000000000000100 F -b00000000000000000000000000000101 G +b00000000000000000000000000000001 F b00000000000000000000000000000100 H -b00000000000000000000000000000101 K -b00000000000000000000000000000101 L +b00000000000000000000000000000001 J +b00000000000000000000000000000001 K +b00000000000000000000000000000100 L b00000000000000000000000000000100 M -b00000000000000000000000000000100 O -b00000000000000000000000000000101 P -b00000000000000000000000000000101 Q +b00000000000000000000000000000001 O +b00000000000000000000000000000100 Q b00000000000000000000000000000100 R -b00000000000000000000000000000100 T -b00000000000000000000000000000101 U -b00000000000000000000000000000101 V -1W -b00000000000000000000000000000001 X -b00000000000000000000000000000110 Y -b00000000000000000000000000000101 Z +b00000000000000000000000000000001 T +b00000000000000000000000000000100 V +b00000000000000000000000000000100 W +1X +b00000000000000000000000000000100 Z b00000000000000000000000000000001 \ -#55 -0W -#60 -b00000000000000000000000000000111 & -b00000111 ' -b00000000000000000000000000000110 ( -b00000000000000000000000000000110 * +#45 +0X +#50 +b00000000000000000000000000000110 ' +b00000110 ( +b00000000000000000000000000000101 ) b00000000000000000000000000000101 + -b00000000000000000000000000000101 - -b00000000000000000000000000000101 / -b00000000000000000000000000000101 1 -b00000000000000000000000000000101 3 -b00000000000000000000000000000101 5 -b00000000000000000000000000000011 9 -b00000000000000000000000000000100 = -b00000000000000000000000000000110 ? +b00000000000000000000000000000100 , +b00000000000000000000000000000100 . +b00000000000000000000000000000100 0 +b00000000000000000000000000000100 2 +b00000000000000000000000000000100 4 +b00000000000000000000000000000100 6 +b00000000000000000000000000000001 ; +b00000000000000000000000000000001 = b00000000000000000000000000000101 @ -b00000000000000000000000000000101 B -b00000000000000000000000000000110 C +b00000000000000000000000000000100 A +b00000000000000000000000000000100 C b00000000000000000000000000000101 D -b00000000000000000000000000000101 F -b00000000000000000000000000000110 G +b00000000000000000000000000000100 E +b00000000000000000000000000000100 G b00000000000000000000000000000101 H -b00000000000000000000000000000110 K -b00000000000000000000000000000110 L +b00000000000000000000000000000100 I +b00000000000000000000000000000101 L b00000000000000000000000000000101 M -b00000000000000000000000000000101 O -b00000000000000000000000000000110 P -b00000000000000000000000000000110 Q +b00000000000000000000000000000100 N +b00000000000000000000000000000100 P +b00000000000000000000000000000101 Q b00000000000000000000000000000101 R -b00000000000000000000000000000101 T -b00000000000000000000000000000110 U -b00000000000000000000000000000110 V -1W -b00000000000000000000000000000111 Y +b00000000000000000000000000000100 S +b00000000000000000000000000000100 U +b00000000000000000000000000000101 V +b00000000000000000000000000000101 W +1X +b00000000000000000000000000000001 Y b00000000000000000000000000000110 Z -#65 -0W -#70 -b00000000000000000000000000001000 & -b00001000 ' -b00000000000000000000000000000111 ( -b00000000000000000000000000000111 * +b00000000000000000000000000000101 [ +b00000000000000000000000000000001 ] +#55 +0X +#60 +b00000000000000000000000000000111 ' +b00000111 ( +b00000000000000000000000000000110 ) b00000000000000000000000000000110 + -b00000000000000000000000000000110 - -b00000000000000000000000000000110 / -b00000000000000000000000000000110 1 -b00000000000000000000000000000110 3 -b00000000000000000000000000000110 5 -b00000000000000000000000000000100 9 -b00000000000000000000000000000101 = -b00000000000000000000000000000111 ? +b00000000000000000000000000000101 , +b00000000000000000000000000000101 . +b00000000000000000000000000000101 0 +b00000000000000000000000000000101 2 +b00000000000000000000000000000101 4 +b00000000000000000000000000000101 6 +b00000000000000000000000000000011 : +b00000000000000000000000000000100 > b00000000000000000000000000000110 @ -b00000000000000000000000000000110 B -b00000000000000000000000000000111 C +b00000000000000000000000000000101 A +b00000000000000000000000000000101 C b00000000000000000000000000000110 D -b00000000000000000000000000000110 F -b00000000000000000000000000000111 G +b00000000000000000000000000000101 E +b00000000000000000000000000000101 G b00000000000000000000000000000110 H -b00000000000000000000000000000111 K -b00000000000000000000000000000111 L +b00000000000000000000000000000101 I +b00000000000000000000000000000110 L b00000000000000000000000000000110 M -b00000000000000000000000000000110 O -b00000000000000000000000000000111 P -b00000000000000000000000000000111 Q +b00000000000000000000000000000101 N +b00000000000000000000000000000101 P +b00000000000000000000000000000110 Q b00000000000000000000000000000110 R -b00000000000000000000000000000110 T -b00000000000000000000000000000111 U -b00000000000000000000000000000111 V -1W -b00000000000000000000000000001000 Y +b00000000000000000000000000000101 S +b00000000000000000000000000000101 U +b00000000000000000000000000000110 V +b00000000000000000000000000000110 W +1X b00000000000000000000000000000111 Z -#75 -0W -#80 -b00000000000000000000000000001001 & -b00001001 ' -b00000000000000000000000000001000 ( -b00000000000000000000000000001000 * +b00000000000000000000000000000110 [ +#65 +0X +#70 +b00000000000000000000000000001000 ' +b00001000 ( +b00000000000000000000000000000111 ) b00000000000000000000000000000111 + -b00000000000000000000000000000111 - -b00000000000000000000000000000111 / -b00000000000000000000000000000111 1 -b00000000000000000000000000000111 3 -b00000000000000000000000000000111 5 -b00000000000000000000000000000101 9 -b00000000000000000000000000000110 = -b00000000000000000000000000001000 ? +b00000000000000000000000000000110 , +b00000000000000000000000000000110 . +b00000000000000000000000000000110 0 +b00000000000000000000000000000110 2 +b00000000000000000000000000000110 4 +b00000000000000000000000000000110 6 +b00000000000000000000000000000100 : +b00000000000000000000000000000101 > b00000000000000000000000000000111 @ -b00000000000000000000000000000111 B -b00000000000000000000000000001000 C +b00000000000000000000000000000110 A +b00000000000000000000000000000110 C b00000000000000000000000000000111 D -b00000000000000000000000000000111 F -b00000000000000000000000000001000 G +b00000000000000000000000000000110 E +b00000000000000000000000000000110 G b00000000000000000000000000000111 H -b00000000000000000000000000001000 K -b00000000000000000000000000001000 L +b00000000000000000000000000000110 I +b00000000000000000000000000000111 L b00000000000000000000000000000111 M -b00000000000000000000000000000111 O -b00000000000000000000000000001000 P -b00000000000000000000000000001000 Q +b00000000000000000000000000000110 N +b00000000000000000000000000000110 P +b00000000000000000000000000000111 Q b00000000000000000000000000000111 R -b00000000000000000000000000000111 T -b00000000000000000000000000001000 U -b00000000000000000000000000001000 V -1W -b00000000000000000000000000001001 Y +b00000000000000000000000000000110 S +b00000000000000000000000000000110 U +b00000000000000000000000000000111 V +b00000000000000000000000000000111 W +1X b00000000000000000000000000001000 Z -#85 -0W -#90 -b00000000000000000000000000001010 & -b00001010 ' -b00000000000000000000000000001001 ( -b00000000000000000000000000001001 * +b00000000000000000000000000000111 [ +#75 +0X +#80 +b00000000000000000000000000001001 ' +b00001001 ( +b00000000000000000000000000001000 ) b00000000000000000000000000001000 + -b00000000000000000000000000001000 - -b00000000000000000000000000001000 / -b00000000000000000000000000001000 1 -b00000000000000000000000000001000 3 -b00000000000000000000000000001000 5 -b00000000000000000000000000000110 9 -b00000000000000000000000000000111 = -b00000000000000000000000000001001 ? +b00000000000000000000000000000111 , +b00000000000000000000000000000111 . +b00000000000000000000000000000111 0 +b00000000000000000000000000000111 2 +b00000000000000000000000000000111 4 +b00000000000000000000000000000111 6 +b00000000000000000000000000000101 : +b00000000000000000000000000000110 > b00000000000000000000000000001000 @ -b00000000000000000000000000001000 B -b00000000000000000000000000001001 C +b00000000000000000000000000000111 A +b00000000000000000000000000000111 C b00000000000000000000000000001000 D -b00000000000000000000000000001000 F -b00000000000000000000000000001001 G +b00000000000000000000000000000111 E +b00000000000000000000000000000111 G b00000000000000000000000000001000 H -b00000000000000000000000000001001 K -b00000000000000000000000000001001 L +b00000000000000000000000000000111 I +b00000000000000000000000000001000 L b00000000000000000000000000001000 M -b00000000000000000000000000001000 O -b00000000000000000000000000001001 P -b00000000000000000000000000001001 Q +b00000000000000000000000000000111 N +b00000000000000000000000000000111 P +b00000000000000000000000000001000 Q b00000000000000000000000000001000 R -b00000000000000000000000000001000 T -b00000000000000000000000000001001 U -b00000000000000000000000000001001 V -1W -b00000000000000000000000000001010 Y +b00000000000000000000000000000111 S +b00000000000000000000000000000111 U +b00000000000000000000000000001000 V +b00000000000000000000000000001000 W +1X b00000000000000000000000000001001 Z -#95 -0W -#100 -b00000000000000000000000000001011 & -b00001011 ' -b00000000000000000000000000001010 ( -b00000000000000000000000000001010 * +b00000000000000000000000000001000 [ +#85 +0X +#90 +b00000000000000000000000000001010 ' +b00001010 ( +b00000000000000000000000000001001 ) b00000000000000000000000000001001 + -b00000000000000000000000000001001 - -b00000000000000000000000000001001 / -b00000000000000000000000000001001 1 -b00000000000000000000000000001001 3 -b00000000000000000000000000001001 5 -b00000000000000000000000000000111 9 -b00000000000000000000000000000001 > -b00000000000000000000000000001010 ? +b00000000000000000000000000001000 , +b00000000000000000000000000001000 . +b00000000000000000000000000001000 0 +b00000000000000000000000000001000 2 +b00000000000000000000000000001000 4 +b00000000000000000000000000001000 6 +b00000000000000000000000000000110 : +b00000000000000000000000000000111 > b00000000000000000000000000001001 @ -b00000000000000000000000000001001 B -b00000000000000000000000000001010 C +b00000000000000000000000000001000 A +b00000000000000000000000000001000 C b00000000000000000000000000001001 D -b00000000000000000000000000001001 F -b00000000000000000000000000001010 G +b00000000000000000000000000001000 E +b00000000000000000000000000001000 G b00000000000000000000000000001001 H -b00000000000000000000000000001010 K -b00000000000000000000000000001010 L +b00000000000000000000000000001000 I +b00000000000000000000000000001001 L b00000000000000000000000000001001 M -b00000000000000000000000000001001 O -b00000000000000000000000000001010 P -b00000000000000000000000000001010 Q +b00000000000000000000000000001000 N +b00000000000000000000000000001000 P +b00000000000000000000000000001001 Q b00000000000000000000000000001001 R -b00000000000000000000000000001001 T -b00000000000000000000000000001010 U -b00000000000000000000000000001010 V -1W -b00000000000000000000000000001011 Y +b00000000000000000000000000001000 S +b00000000000000000000000000001000 U +b00000000000000000000000000001001 V +b00000000000000000000000000001001 W +1X b00000000000000000000000000001010 Z +b00000000000000000000000000001001 [ +#95 +0X +#100 +b00000000000000000000000000001011 ' +b00001011 ( +b00000000000000000000000000001010 ) +b00000000000000000000000000001010 + +b00000000000000000000000000001001 , +b00000000000000000000000000001001 . +b00000000000000000000000000001001 0 +b00000000000000000000000000001001 2 +b00000000000000000000000000001001 4 +b00000000000000000000000000001001 6 +b00000000000000000000000000000111 : +b00000000000000000000000000000001 ? +b00000000000000000000000000001010 @ +b00000000000000000000000000001001 A +b00000000000000000000000000001001 C +b00000000000000000000000000001010 D +b00000000000000000000000000001001 E +b00000000000000000000000000001001 G +b00000000000000000000000000001010 H +b00000000000000000000000000001001 I +b00000000000000000000000000001010 L +b00000000000000000000000000001010 M +b00000000000000000000000000001001 N +b00000000000000000000000000001001 P +b00000000000000000000000000001010 Q +b00000000000000000000000000001010 R +b00000000000000000000000000001001 S +b00000000000000000000000000001001 U +b00000000000000000000000000001010 V +b00000000000000000000000000001010 W +1X +b00000000000000000000000000001011 Z +b00000000000000000000000000001010 [ diff --git a/test_regress/t/t_cover_line_trace.pl b/test_regress/t/t_cover_line_trace.pl index a3763b8c5..7d52a768f 100755 --- a/test_regress/t/t_cover_line_trace.pl +++ b/test_regress/t/t_cover_line_trace.pl @@ -21,6 +21,7 @@ execute( ); run(cmd => ["../bin/verilator_coverage", + "--annotate-points", "--annotate", "$Self->{obj_dir}/annotated", "$Self->{obj_dir}/coverage.dat", ], diff --git a/test_regress/t/t_cover_toggle.out b/test_regress/t/t_cover_toggle.out index d9dd61b7d..3baf9007b 100644 --- a/test_regress/t/t_cover_toggle.out +++ b/test_regress/t/t_cover_toggle.out @@ -1,162 +1,162 @@ - // verilator_coverage annotation - // DESCRIPTION: Verilator: Verilog Test module - // - // This file ONLY is placed under the Creative Commons Public Domain, for - // any use, without warranty, 2008 by Wilson Snyder. - // SPDX-License-Identifier: CC0-1.0 - - module t (/*AUTOARG*/ - // Inputs - clk, - check_real, - check_string - ); - - 000019 input clk; - input real check_real; // Check issue #2741 - input string check_string; // Check issue #2766 - - typedef struct packed { - union packed { - logic ua; - logic ub; - } u; - logic b; - } str_t; - -%000002 reg toggle; initial toggle='0; - -%000004 str_t stoggle; initial stoggle='0; - - const reg aconst = '0; - -%000002 reg [1:0][1:0] ptoggle; initial ptoggle=0; - - integer cyc; initial cyc=1; - 000019 wire [7:0] cyc_copy = cyc[7:0]; -%000002 wire toggle_up; - - alpha a1 (/*AUTOINST*/ - // Outputs - .toggle_up (toggle_up), - // Inputs - .clk (clk), - .toggle (toggle), - .cyc_copy (cyc_copy[7:0])); - alpha a2 (/*AUTOINST*/ - // Outputs - .toggle_up (toggle_up), - // Inputs - .clk (clk), - .toggle (toggle), - .cyc_copy (cyc_copy[7:0])); - - beta b1 (/*AUTOINST*/ - // Inputs - .clk (clk), - .toggle_up (toggle_up)); - - off o1 (/*AUTOINST*/ - // Inputs - .clk (clk), - .toggle (toggle)); - -%000001 reg [1:0] memory[121:110]; - - wire [1023:0] largeish = {992'h0, cyc}; - // CHECK_COVER_MISSING(-1) - - always @ (posedge clk) begin - if (cyc!=0) begin - cyc <= cyc + 1; - memory[cyc + 'd100] <= memory[cyc + 'd100] + 2'b1; - toggle <= '0; - stoggle.u <= toggle; - stoggle.b <= toggle; - ptoggle[0][0] <= toggle; - if (cyc==3) begin - toggle <= '1; - end - if (cyc==4) begin - toggle <= '0; - end - else if (cyc==10) begin - $write("*-* All Finished *-*\n"); - $finish; - end - end - end - - endmodule - - module alpha (/*AUTOARG*/ - // Outputs - toggle_up, - // Inputs - clk, toggle, cyc_copy - ); - - // t.a1 and t.a2 collapse to a count of 2 - - 000038 input clk; - -%000004 input toggle; - // CHECK_COVER(-1,"top.t.a*",4) - // 2 edges * (t.a1 and t.a2) - - 000038 input [7:0] cyc_copy; - // CHECK_COVER(-1,"top.t.a*","cyc_copy[0]",22) - // CHECK_COVER(-2,"top.t.a*","cyc_copy[1]",10) - // CHECK_COVER(-3,"top.t.a*","cyc_copy[2]",4) - // CHECK_COVER(-4,"top.t.a*","cyc_copy[3]",2) - // CHECK_COVER(-5,"top.t.a*","cyc_copy[4]",0) - // CHECK_COVER(-6,"top.t.a*","cyc_copy[5]",0) - // CHECK_COVER(-7,"top.t.a*","cyc_copy[6]",0) - // CHECK_COVER(-8,"top.t.a*","cyc_copy[7]",0) - -%000004 reg toggle_internal; - // CHECK_COVER(-1,"top.t.a*",4) - // 2 edges * (t.a1 and t.a2) - -%000004 output reg toggle_up; - // CHECK_COVER(-1,"top.t.a*",4) - // 2 edges * (t.a1 and t.a2) - - always @ (posedge clk) begin - toggle_internal <= toggle; - toggle_up <= toggle; - end - endmodule - - module beta (/*AUTOARG*/ - // Inputs - clk, toggle_up - ); - - 000019 input clk; - -%000002 input toggle_up; - // CHECK_COVER(-1,"top.t.b1","toggle_up",2) - - /* verilator public_module */ - - always @ (posedge clk) begin - if (0 && toggle_up) begin end - end - endmodule - - module off (/*AUTOARG*/ - // Inputs - clk, toggle - ); - - // verilator coverage_off - input clk; - // CHECK_COVER_MISSING(-1) - - // verilator coverage_on -%000002 input toggle; - // CHECK_COVER(-1,"top.t.o1","toggle",2) - - endmodule - +// // verilator_coverage annotation + // DESCRIPTION: Verilator: Verilog Test module + // + // This file ONLY is placed under the Creative Commons Public Domain, for + // any use, without warranty, 2008 by Wilson Snyder. + // SPDX-License-Identifier: CC0-1.0 + + module t (/*AUTOARG*/ + // Inputs + clk, + check_real, + check_string + ); + + 000019 input clk; + input real check_real; // Check issue #2741 + input string check_string; // Check issue #2766 + + typedef struct packed { + union packed { + logic ua; + logic ub; + } u; + logic b; + } str_t; + +%000002 reg toggle; initial toggle='0; + +%000002 str_t stoggle; initial stoggle='0; + + const reg aconst = '0; + +%000000 reg [1:0][1:0] ptoggle; initial ptoggle=0; + + integer cyc; initial cyc=1; +%000000 wire [7:0] cyc_copy = cyc[7:0]; +%000002 wire toggle_up; + + alpha a1 (/*AUTOINST*/ + // Outputs + .toggle_up (toggle_up), + // Inputs + .clk (clk), + .toggle (toggle), + .cyc_copy (cyc_copy[7:0])); + alpha a2 (/*AUTOINST*/ + // Outputs + .toggle_up (toggle_up), + // Inputs + .clk (clk), + .toggle (toggle), + .cyc_copy (cyc_copy[7:0])); + + beta b1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle_up (toggle_up)); + + off o1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + +%000000 reg [1:0] memory[121:110]; + + wire [1023:0] largeish = {992'h0, cyc}; + // CHECK_COVER_MISSING(-1) + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + memory[cyc + 'd100] <= memory[cyc + 'd100] + 2'b1; + toggle <= '0; + stoggle.u <= toggle; + stoggle.b <= toggle; + ptoggle[0][0] <= toggle; + if (cyc==3) begin + toggle <= '1; + end + if (cyc==4) begin + toggle <= '0; + end + else if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + + endmodule + + module alpha (/*AUTOARG*/ + // Outputs + toggle_up, + // Inputs + clk, toggle, cyc_copy + ); + + // t.a1 and t.a2 collapse to a count of 2 + + 000038 input clk; + +%000004 input toggle; + // CHECK_COVER(-1,"top.t.a*",4) + // 2 edges * (t.a1 and t.a2) + +%000000 input [7:0] cyc_copy; + // CHECK_COVER(-1,"top.t.a*","cyc_copy[0]",22) + // CHECK_COVER(-2,"top.t.a*","cyc_copy[1]",10) + // CHECK_COVER(-3,"top.t.a*","cyc_copy[2]",4) + // CHECK_COVER(-4,"top.t.a*","cyc_copy[3]",2) + // CHECK_COVER(-5,"top.t.a*","cyc_copy[4]",0) + // CHECK_COVER(-6,"top.t.a*","cyc_copy[5]",0) + // CHECK_COVER(-7,"top.t.a*","cyc_copy[6]",0) + // CHECK_COVER(-8,"top.t.a*","cyc_copy[7]",0) + +%000004 reg toggle_internal; + // CHECK_COVER(-1,"top.t.a*",4) + // 2 edges * (t.a1 and t.a2) + +%000004 output reg toggle_up; + // CHECK_COVER(-1,"top.t.a*",4) + // 2 edges * (t.a1 and t.a2) + + always @ (posedge clk) begin + toggle_internal <= toggle; + toggle_up <= toggle; + end + endmodule + + module beta (/*AUTOARG*/ + // Inputs + clk, toggle_up + ); + + 000019 input clk; + +%000002 input toggle_up; + // CHECK_COVER(-1,"top.t.b1","toggle_up",2) + + /* verilator public_module */ + + always @ (posedge clk) begin + if (0 && toggle_up) begin end + end + endmodule + + module off (/*AUTOARG*/ + // Inputs + clk, toggle + ); + + // verilator coverage_off + input clk; + // CHECK_COVER_MISSING(-1) + + // verilator coverage_on +%000002 input toggle; + // CHECK_COVER(-1,"top.t.o1","toggle",2) + + endmodule + diff --git a/test_regress/t/t_cover_toggle.pl b/test_regress/t/t_cover_toggle.pl index 5564c29d5..45cfb4989 100755 --- a/test_regress/t/t_cover_toggle.pl +++ b/test_regress/t/t_cover_toggle.pl @@ -35,5 +35,15 @@ run(cmd => ["../bin/verilator_coverage", files_identical("$Self->{obj_dir}/annotated/$Self->{name}.v", $Self->{golden_filename}); +run(cmd => ["../bin/verilator_coverage", + "--annotate-points", + "--annotate", "$Self->{obj_dir}/annotated-points", + "$Self->{obj_dir}/coverage.dat", + ], + verilator_run => 1, + ); + +files_identical("$Self->{obj_dir}/annotated-points/$Self->{name}.v", "t/" . $Self->{name} . "_points.out"); + ok(1); 1; diff --git a/test_regress/t/t_cover_toggle_points.out b/test_regress/t/t_cover_toggle_points.out new file mode 100644 index 000000000..120ddeebd --- /dev/null +++ b/test_regress/t/t_cover_toggle_points.out @@ -0,0 +1,218 @@ +// // verilator_coverage annotation + // DESCRIPTION: Verilator: Verilog Test module + // + // This file ONLY is placed under the Creative Commons Public Domain, for + // any use, without warranty, 2008 by Wilson Snyder. + // SPDX-License-Identifier: CC0-1.0 + + module t (/*AUTOARG*/ + // Inputs + clk, + check_real, + check_string + ); + + 000019 input clk; ++000019 point: comment=clk + input real check_real; // Check issue #2741 + input string check_string; // Check issue #2766 + + typedef struct packed { + union packed { + logic ua; + logic ub; + } u; + logic b; + } str_t; + +%000002 reg toggle; initial toggle='0; +-000002 point: comment=toggle + +%000002 str_t stoggle; initial stoggle='0; +-000002 point: comment=stoggle.b +-000002 point: comment=stoggle.u.ua + + const reg aconst = '0; + +%000000 reg [1:0][1:0] ptoggle; initial ptoggle=0; +-000002 point: comment=ptoggle[0][0] +-000000 point: comment=ptoggle[0][1] +-000000 point: comment=ptoggle[1][0] +-000000 point: comment=ptoggle[1][1] + + integer cyc; initial cyc=1; +%000000 wire [7:0] cyc_copy = cyc[7:0]; ++000011 point: comment=cyc_copy[0] +-000005 point: comment=cyc_copy[1] +-000002 point: comment=cyc_copy[2] +-000001 point: comment=cyc_copy[3] +-000000 point: comment=cyc_copy[4] +-000000 point: comment=cyc_copy[5] +-000000 point: comment=cyc_copy[6] +-000000 point: comment=cyc_copy[7] +%000002 wire toggle_up; +-000002 point: comment=toggle_up + + alpha a1 (/*AUTOINST*/ + // Outputs + .toggle_up (toggle_up), + // Inputs + .clk (clk), + .toggle (toggle), + .cyc_copy (cyc_copy[7:0])); + alpha a2 (/*AUTOINST*/ + // Outputs + .toggle_up (toggle_up), + // Inputs + .clk (clk), + .toggle (toggle), + .cyc_copy (cyc_copy[7:0])); + + beta b1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle_up (toggle_up)); + + off o1 (/*AUTOINST*/ + // Inputs + .clk (clk), + .toggle (toggle)); + +%000000 reg [1:0] memory[121:110]; +-000001 point: comment=memory[110][0] +-000000 point: comment=memory[110][1] +-000000 point: comment=memory[111][0] +-000000 point: comment=memory[111][1] +-000000 point: comment=memory[112][0] +-000000 point: comment=memory[112][1] +-000000 point: comment=memory[113][0] +-000000 point: comment=memory[113][1] +-000000 point: comment=memory[114][0] +-000000 point: comment=memory[114][1] +-000000 point: comment=memory[115][0] +-000000 point: comment=memory[115][1] +-000000 point: comment=memory[116][0] +-000000 point: comment=memory[116][1] +-000000 point: comment=memory[117][0] +-000000 point: comment=memory[117][1] +-000000 point: comment=memory[118][0] +-000000 point: comment=memory[118][1] +-000000 point: comment=memory[119][0] +-000000 point: comment=memory[119][1] +-000000 point: comment=memory[120][0] +-000000 point: comment=memory[120][1] +-000000 point: comment=memory[121][0] +-000000 point: comment=memory[121][1] + + wire [1023:0] largeish = {992'h0, cyc}; + // CHECK_COVER_MISSING(-1) + + always @ (posedge clk) begin + if (cyc!=0) begin + cyc <= cyc + 1; + memory[cyc + 'd100] <= memory[cyc + 'd100] + 2'b1; + toggle <= '0; + stoggle.u <= toggle; + stoggle.b <= toggle; + ptoggle[0][0] <= toggle; + if (cyc==3) begin + toggle <= '1; + end + if (cyc==4) begin + toggle <= '0; + end + else if (cyc==10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + end + + endmodule + + module alpha (/*AUTOARG*/ + // Outputs + toggle_up, + // Inputs + clk, toggle, cyc_copy + ); + + // t.a1 and t.a2 collapse to a count of 2 + + 000038 input clk; ++000038 point: comment=clk + +%000004 input toggle; +-000004 point: comment=toggle + // CHECK_COVER(-1,"top.t.a*",4) + // 2 edges * (t.a1 and t.a2) + +%000000 input [7:0] cyc_copy; ++000022 point: comment=cyc_copy[0] ++000010 point: comment=cyc_copy[1] +-000004 point: comment=cyc_copy[2] +-000002 point: comment=cyc_copy[3] +-000000 point: comment=cyc_copy[4] +-000000 point: comment=cyc_copy[5] +-000000 point: comment=cyc_copy[6] +-000000 point: comment=cyc_copy[7] + // CHECK_COVER(-1,"top.t.a*","cyc_copy[0]",22) + // CHECK_COVER(-2,"top.t.a*","cyc_copy[1]",10) + // CHECK_COVER(-3,"top.t.a*","cyc_copy[2]",4) + // CHECK_COVER(-4,"top.t.a*","cyc_copy[3]",2) + // CHECK_COVER(-5,"top.t.a*","cyc_copy[4]",0) + // CHECK_COVER(-6,"top.t.a*","cyc_copy[5]",0) + // CHECK_COVER(-7,"top.t.a*","cyc_copy[6]",0) + // CHECK_COVER(-8,"top.t.a*","cyc_copy[7]",0) + +%000004 reg toggle_internal; +-000004 point: comment=toggle_internal + // CHECK_COVER(-1,"top.t.a*",4) + // 2 edges * (t.a1 and t.a2) + +%000004 output reg toggle_up; +-000004 point: comment=toggle_up + // CHECK_COVER(-1,"top.t.a*",4) + // 2 edges * (t.a1 and t.a2) + + always @ (posedge clk) begin + toggle_internal <= toggle; + toggle_up <= toggle; + end + endmodule + + module beta (/*AUTOARG*/ + // Inputs + clk, toggle_up + ); + + 000019 input clk; ++000019 point: comment=clk + +%000002 input toggle_up; +-000002 point: comment=toggle_up + // CHECK_COVER(-1,"top.t.b1","toggle_up",2) + + /* verilator public_module */ + + always @ (posedge clk) begin + if (0 && toggle_up) begin end + end + endmodule + + module off (/*AUTOARG*/ + // Inputs + clk, toggle + ); + + // verilator coverage_off + input clk; + // CHECK_COVER_MISSING(-1) + + // verilator coverage_on +%000002 input toggle; +-000002 point: comment=toggle + // CHECK_COVER(-1,"top.t.o1","toggle",2) + + endmodule + diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index 7ef0ebebd..82db5dfde 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -7,24 +7,15 @@ module Vt_debug_emitv_t; ???? // ENUMITEM 'ZERO' 32'h0 ???? // ENUMITEM 'ONE' - 32'h1 - ???? // REFDTYPE 'e_t' - struct packed - { - ???? // REFDTYPE 'e_t' - a}signed logic [2:0] struct - {signed logic [2:0] a}logicunion - {logic a} - ???? // REFDTYPE 'ps_t' - bit [31:0] const - ???? // REFDTYPE 'ps_t' - const - ???? // REFDTYPE 'ps_t' - [0:2] - ???? // REFDTYPE 'us_t' - - ???? // REFDTYPE 'union_t' - signed int [31:0] signed int [31:0] [0:2]logic [15:0] logic [15:0] logic [15:0] signed int [31:0] signed int [31:0] signed int [31:0] + 32'h1signed int [31:0] struct packed + {signed int [31:0] a;}signed logic [2:0] struct + {signed logic [2:0] a;}logicunion + {logic a;}struct packed + {signed int [31:0] a;}bit [31:0] const struct packed + {signed int [31:0] a;}const struct packed + {signed int [31:0] a;}[0:2]struct + {signed logic [2:0] a;}union + {logic a;}signed int [31:0] signed int [31:0] [0:2]logic [15:0] logic [15:0] logic [15:0] signed int [31:0] signed int [31:0] signed int [31:0] ???? // QUEUEDTYPE signed int [31:0] string ???? // ASSOCARRAYDTYPE @@ -34,21 +25,14 @@ module Vt_debug_emitv_t; ???? // DYNARRAYDTYPE signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed realstringIData [31:0] signed logic [31:0] signed int [31:0] bit [0:0] logic [0:0] e_t; typedef struct packed - { - ???? // REFDTYPE 'e_t' - a}signed logic [2:0] struct - {signed logic [2:0] a}logicunion - {logic a} - ???? // REFDTYPE 'ps_t' - bit [31:0] const - ???? // REFDTYPE 'ps_t' - const - ???? // REFDTYPE 'ps_t' - [0:2] - ???? // REFDTYPE 'us_t' - - ???? // REFDTYPE 'union_t' - signed int [31:0] signed int [31:0] [0:2]logic [15:0] logic [15:0] logic [15:0] signed int [31:0] signed int [31:0] signed int [31:0] + {signed int [31:0] a;}signed logic [2:0] struct + {signed logic [2:0] a;}logicunion + {logic a;}struct packed + {signed int [31:0] a;}bit [31:0] const struct packed + {signed int [31:0] a;}const struct packed + {signed int [31:0] a;}[0:2]struct + {signed logic [2:0] a;}union + {logic a;}signed int [31:0] signed int [31:0] [0:2]logic [15:0] logic [15:0] logic [15:0] signed int [31:0] signed int [31:0] signed int [31:0] ???? // QUEUEDTYPE signed int [31:0] string ???? // ASSOCARRAYDTYPE @@ -58,18 +42,13 @@ module Vt_debug_emitv_t; ???? // DYNARRAYDTYPE signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed realstringIData [31:0] signed logic [31:0] signed int [31:0] bit [0:0] logic [0:0] ps_t; typedef struct - {signed logic [2:0] a}logicunion - {logic a} - ???? // REFDTYPE 'ps_t' - bit [31:0] const - ???? // REFDTYPE 'ps_t' - const - ???? // REFDTYPE 'ps_t' - [0:2] - ???? // REFDTYPE 'us_t' - - ???? // REFDTYPE 'union_t' - signed int [31:0] signed int [31:0] [0:2]logic [15:0] logic [15:0] logic [15:0] signed int [31:0] signed int [31:0] signed int [31:0] + {signed logic [2:0] a;}logicunion + {logic a;}struct packed + {signed int [31:0] a;}bit [31:0] const struct packed + {signed int [31:0] a;}const struct packed + {signed int [31:0] a;}[0:2]struct + {signed logic [2:0] a;}union + {logic a;}signed int [31:0] signed int [31:0] [0:2]logic [15:0] logic [15:0] logic [15:0] signed int [31:0] signed int [31:0] signed int [31:0] ???? // QUEUEDTYPE signed int [31:0] string ???? // ASSOCARRAYDTYPE @@ -79,17 +58,12 @@ module Vt_debug_emitv_t; ???? // DYNARRAYDTYPE signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed realstringIData [31:0] signed logic [31:0] signed int [31:0] bit [0:0] logic [0:0] us_t; typedef union - {logic a} - ???? // REFDTYPE 'ps_t' - bit [31:0] const - ???? // REFDTYPE 'ps_t' - const - ???? // REFDTYPE 'ps_t' - [0:2] - ???? // REFDTYPE 'us_t' - - ???? // REFDTYPE 'union_t' - signed int [31:0] signed int [31:0] [0:2]logic [15:0] logic [15:0] logic [15:0] signed int [31:0] signed int [31:0] signed int [31:0] + {logic a;}struct packed + {signed int [31:0] a;}bit [31:0] const struct packed + {signed int [31:0] a;}const struct packed + {signed int [31:0] a;}[0:2]struct + {signed logic [2:0] a;}union + {logic a;}signed int [31:0] signed int [31:0] [0:2]logic [15:0] logic [15:0] logic [15:0] signed int [31:0] signed int [31:0] signed int [31:0] ???? // QUEUEDTYPE signed int [31:0] string ???? // ASSOCARRAYDTYPE @@ -99,13 +73,11 @@ module Vt_debug_emitv_t; ???? // DYNARRAYDTYPE signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed int [31:0] signed realstringIData [31:0] signed logic [31:0] signed int [31:0] bit [0:0] logic [0:0] union_t; struct packed - { - ???? // REFDTYPE 'e_t' - a} ps[0:2]; + {signed int [31:0] a;} ps[0:2]; struct - {signed logic [2:0] a} us; + {signed logic [2:0] a;} us; union - {logic a} unu; + {logic a;} unu; signed int [31:0] array[0:2]; initial begin array = '{0:32'sh1, 1:32'sh2, 2:32'sh3}; diff --git a/test_regress/t/t_debug_emitv.pl b/test_regress/t/t_debug_emitv.pl index 91be564c7..4af48a3e3 100755 --- a/test_regress/t/t_debug_emitv.pl +++ b/test_regress/t/t_debug_emitv.pl @@ -16,7 +16,7 @@ lint( v_flags => ["--lint-only --dumpi-tree 9 --dumpi-V3EmitV 9 --debug-emitv"], ); -files_identical(glob_one("$Self->{obj_dir}/$Self->{VM_PREFIX}_*_width.tree.v"), $Self->{golden_filename}); +files_identical(glob_one("$Self->{obj_dir}/$Self->{vm_prefix}_*_width.tree.v"), $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_delay_var.out b/test_regress/t/t_delay_var.out new file mode 100644 index 000000000..7c78068df --- /dev/null +++ b/test_regress/t/t_delay_var.out @@ -0,0 +1,5 @@ +%Error-ZERODLY: t/t_delay_var.v:20:7: Unsupported: #0 delays do not schedule process resumption in the Inactive region + 20 | #0 in = 1'b1; + | ^ + ... For error description see https://verilator.org/warn/ZERODLY?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_delay_var.pl b/test_regress/t/t_delay_var.pl new file mode 100755 index 000000000..c0d64fbeb --- /dev/null +++ b/test_regress/t/t_delay_var.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + fails => $Self->{vlt}, + expect_filename => $Self->{golden_filename}, + ); + + execute( + check_finished => 1, + ) if !$Self->{vlt}; +} + +ok(1); +1; diff --git a/test_regress/t/t_delay_var.v b/test_regress/t/t_delay_var.v new file mode 100644 index 000000000..b303a45f0 --- /dev/null +++ b/test_regress/t/t_delay_var.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + parameter PDLY = 1.2; + real rdly = 1.3; + integer idly = 1; + + reg in = 1'b0; + + wire #1.1 d_const = in; + wire #idly d_int = in; + wire #rdly d_real = in; + wire #PDLY d_param = in; + + initial begin + #0 in = 1'b1; + #2 in = 1'b0; + #100; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dict_ref_type.pl b/test_regress/t/t_dict_ref_type.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_dict_ref_type.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dict_ref_type.v b/test_regress/t/t_dict_ref_type.v new file mode 100644 index 000000000..b7dbc854f --- /dev/null +++ b/test_regress/t/t_dict_ref_type.v @@ -0,0 +1,68 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Foo1; + int x = 1; + function int get_x; + return x; + endfunction +endclass + +class Foo2; + int x = 2; + function int get_x; + return x; + endfunction +endclass + +class Bar; + typedef Foo1 foo_t; + protected foo_t m_dict[int]; + + function void set(int key); + foo_t default_value = new; + m_dict[key] = default_value; + endfunction + function foo_t get(int key); + return m_dict[key]; + endfunction +endclass + +class Baz #(type T=Foo1); + protected T m_dict[int]; + + function void set(int key); + T default_value = new; + m_dict[key] = default_value; + endfunction + function T get(int key); + return m_dict[key]; + endfunction +endclass + +module t (/*AUTOARG*/ + ); + + initial begin + Bar bar_i = new; + Baz baz_1_i = new; + Baz #(Foo2) baz_2_i = new; + + bar_i.set(1); + baz_1_i.set(2); + baz_2_i.set(3); + + if (bar_i.get(1).get_x() == 1 && + baz_1_i.get(2).get_x() == 1 && + baz_2_i.get(3).get_x() == 2) begin + $write("*-* All Finished *-*\n"); + $finish; + end + else begin + $stop; + end + end +endmodule diff --git a/test_regress/t/t_display_cwide_bad.out b/test_regress/t/t_display_cwide_bad.out index f054ce1b7..604986459 100644 --- a/test_regress/t/t_display_cwide_bad.out +++ b/test_regress/t/t_display_cwide_bad.out @@ -1,6 +1,6 @@ -%Warning-WIDTH: t/t_display_cwide_bad.v:10:7: $display-like format of %c format of > 8 bit value +%Warning-WIDTHTRUNC: t/t_display_cwide_bad.v:10:7: $display-like format of %c format of > 8 bit value 10 | $display("%c", 32'h1234); | ^~~~~~~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_display_merge.pl b/test_regress/t/t_display_merge.pl index 27cc0ef25..0de4e1ed6 100755 --- a/test_regress/t/t_display_merge.pl +++ b/test_regress/t/t_display_merge.pl @@ -19,7 +19,7 @@ execute( expect_filename => $Self->{golden_filename}, ); -file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__stats.txt", +file_grep("$Self->{obj_dir}/$Self->{vm_prefix}__stats.txt", qr/Node count, DISPLAY \s+ 44 \s+ 27 \s+ 27 \s+ 6/); ok(1); diff --git a/test_regress/t/t_dist_attributes_bad.h b/test_regress/t/t_dist_attributes_bad.h index bd24cf77f..5b9ed95b7 100644 --- a/test_regress/t/t_dist_attributes_bad.h +++ b/test_regress/t/t_dist_attributes_bad.h @@ -273,4 +273,114 @@ public: } }; +static void static_function() {} + +class StaticClass { +public: + static void static_class_function() {} +}; + +class ConstructorCallsUnsafeLocalFunction { +public: + void unsafe_function() VL_MT_UNSAFE{}; + ConstructorCallsUnsafeLocalFunction() { unsafe_function(); } +}; +class ConstructorCallsStaticFunctionNoAnnotation { +public: + ConstructorCallsStaticFunctionNoAnnotation() { static_function(); } +}; + +class ConstructorCallsLocalFunction { +public: + void local_function() {} + ConstructorCallsLocalFunction() { local_function(); } +}; + +class ConstructorCallsLocalFunctionCallsGlobal { +public: + void local_function() { static_function(); } + ConstructorCallsLocalFunctionCallsGlobal() { local_function(); } +}; + +class SafeFunction { +public: + void safe_function() VL_MT_SAFE {} +}; +class UnsafeFunction { +public: + void unsafe_function() VL_MT_UNSAFE {} +}; + +class ConstructorWithPointer { +public: + ConstructorWithPointer(SafeFunction* p) { p->safe_function(); } +}; + +class ConstructorWithReference { +public: + ConstructorWithReference(SafeFunction& p) { p.safe_function(); } +}; +class ConstructorWithUnsafePointer { +public: + ConstructorWithUnsafePointer(UnsafeFunction* p) { p->unsafe_function(); } +}; + +class ConstructorWithUnsafeReference { +public: + ConstructorWithUnsafeReference(UnsafeFunction& p) { p.unsafe_function(); } +}; + +class ConstructorCallsLocalCallsGlobal { + void local_function2() { static_function(); } + void local_function() { local_function2(); } + +public: + ConstructorCallsLocalCallsGlobal() { local_function(); } +}; + +class ConstructorCallsLocalCallsClassGlobal { + void local_function2() { StaticClass::static_class_function(); } + void local_function() { local_function2(); } + +public: + ConstructorCallsLocalCallsClassGlobal() { local_function(); } +}; + +class TestClassConstructor { + void safe_function_unsafe_constructor_bad() VL_MT_SAFE { + ConstructorCallsUnsafeLocalFunction f{}; + }; + void safe_function_static_constructor_bad() VL_MT_SAFE { + ConstructorCallsStaticFunctionNoAnnotation f{}; + }; + void safe_function_local_function_global_bad() VL_MT_SAFE { + ConstructorCallsLocalFunctionCallsGlobal f{}; + } + void safe_function_local_function_constructor_good() VL_MT_SAFE { + ConstructorCallsLocalFunction f{}; + } + void safe_function_calls_constructor_with_pointer_good() VL_MT_SAFE { + SafeFunction* i = new SafeFunction{}; + ConstructorWithPointer f{i}; + } + void safe_function_calls_constructor_with_reference_good() VL_MT_SAFE { + SafeFunction i; + ConstructorWithReference f{i}; + } + void safe_function_calls_constructor_with_unsafepointer_bad() VL_MT_SAFE { + UnsafeFunction* i = new UnsafeFunction{}; + ConstructorWithUnsafePointer f{i}; + } + void safe_function_calls_constructor_with_unsafereference_bad() VL_MT_SAFE { + UnsafeFunction i; + ConstructorWithUnsafeReference f{i}; + } + void safe_function_calls_constructor_local_calls_global_bad() VL_MT_SAFE { + ConstructorCallsLocalCallsGlobal f{}; + } + void safe_function_calls_constructor_local_calls_class_global_bad() VL_MT_SAFE { + ConstructorCallsLocalCallsClassGlobal f{}; + } +}; + #endif // T_DIST_ATTRIBUTES_BAD_H_ diff --git a/test_regress/t/t_dist_attributes_bad.out b/test_regress/t/t_dist_attributes_bad.out index 71a4bd01b..e7649a02f 100644 --- a/test_regress/t/t_dist_attributes_bad.out +++ b/test_regress/t/t_dist_attributes_bad.out @@ -724,6 +724,34 @@ t/t_dist_attributes_bad.cpp:75: [release] TestClass t/t_dist_attributes_bad.h:124: [] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) [declaration] t/t_dist_attributes_bad.cpp:75: [requires] TestClass::scm_ua_VL_REQUIRES(VerilatedMutex &) +%Error: "TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad()" is mtsafe but calls non-mtsafe function(s) +t/t_dist_attributes_bad.h:381: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_class_global_bad() +t/t_dist_attributes_bad.h:280: [] StaticClass::static_class_function() + +%Error: "TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad()" is mtsafe but calls non-mtsafe function(s) +t/t_dist_attributes_bad.h:378: [mt_safe] TestClassConstructor::safe_function_calls_constructor_local_calls_global_bad() +t/t_dist_attributes_bad.h:276: [] static_function() + +%Error: "TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad()" is mtsafe but calls non-mtsafe function(s) +t/t_dist_attributes_bad.h:370: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafepointer_bad() +t/t_dist_attributes_bad.h:311: [mt_unsafe] UnsafeFunction::unsafe_function() + +%Error: "TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad()" is mtsafe but calls non-mtsafe function(s) +t/t_dist_attributes_bad.h:374: [mt_safe] TestClassConstructor::safe_function_calls_constructor_with_unsafereference_bad() +t/t_dist_attributes_bad.h:311: [mt_unsafe] UnsafeFunction::unsafe_function() + +%Error: "TestClassConstructor::safe_function_local_function_global_bad()" is mtsafe but calls non-mtsafe function(s) +t/t_dist_attributes_bad.h:356: [mt_safe] TestClassConstructor::safe_function_local_function_global_bad() +t/t_dist_attributes_bad.h:276: [] static_function() + +%Error: "TestClassConstructor::safe_function_static_constructor_bad()" is mtsafe but calls non-mtsafe function(s) +t/t_dist_attributes_bad.h:353: [mt_safe] TestClassConstructor::safe_function_static_constructor_bad() +t/t_dist_attributes_bad.h:276: [] static_function() + +%Error: "TestClassConstructor::safe_function_unsafe_constructor_bad()" is mtsafe but calls non-mtsafe function(s) +t/t_dist_attributes_bad.h:350: [mt_safe] TestClassConstructor::safe_function_unsafe_constructor_bad() +t/t_dist_attributes_bad.h:285: [mt_unsafe] ConstructorCallsUnsafeLocalFunction::unsafe_function() + %Error: "ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &)" is mtsafe but calls non-mtsafe function(s) t/t_dist_attributes_bad.cpp:53: [mt_safe] ifh_test_caller_func_VL_MT_SAFE(VerilatedMutex &) t/t_dist_attributes_bad.h:94: [] ifh_NO_ANNOTATION(VerilatedMutex &) @@ -1157,4 +1185,4 @@ t/t_dist_attributes_bad.cpp:60: [mt_unsafe_one] sfc_VL_ t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [release] sfc_VL_RELEASE_SHARED(VerilatedMutex &) t/t_dist_attributes_bad.cpp:60: [requires] sfc_VL_REQUIRES(VerilatedMutex &) -Number of functions reported unsafe: 220 +Number of functions reported unsafe: 224 diff --git a/test_regress/t/t_dist_cinclude.pl b/test_regress/t/t_dist_cinclude.pl index 90b0723b7..da88adfc7 100755 --- a/test_regress/t/t_dist_cinclude.pl +++ b/test_regress/t/t_dist_cinclude.pl @@ -9,49 +9,50 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 use IO::File; +use File::Spec::Functions 'catfile'; scenarios(dist => 1); my $root = ".."; my $Debug; -if (!-r "$root/.git") { +if (!-r catfile($root, ".git")) { skip("Not in a git repository"); } else { ### Must trim output before and after our file list my $files = `cd $root && git ls-files --exclude-standard`; print "ST $files\n" if $Debug; - $files =~ s/\s+/ /g; - my $cmd = "cd $root && fgrep -n include $files | sort"; - my $grep = `$cmd`; - foreach my $line (split /\n/, $grep) { - next if $line =~ m!include/vltstd/vpi_user.h!; # IEEE Standard file - can't change it - next if $line =~ m!include/gtkwave/!; # Standard file - can't change it - my $hit; - $hit = 1 if $line =~ /\bassert\.h/; - $hit = 1 if $line =~ /\bctype\.h/; - $hit = 1 if $line =~ /\berrno\.h/; - $hit = 1 if $line =~ /\bfloat\.h/; - $hit = 1 if $line =~ /\blimits\.h/; - $hit = 1 if $line =~ /\blocale\.h/; - $hit = 1 if $line =~ /\bmath\.h/; - $hit = 1 if $line =~ /\bsetjmp\.h/; - $hit = 1 if $line =~ /\bsignal\.h/; - $hit = 1 if $line =~ /\bstdarg\.h/; - $hit = 1 if $line =~ /\bstdbool\.h/; - $hit = 1 if $line =~ /\bstddef\.h/; - #Not yet: $hit = 1 if $line =~ /\bstdint\.h/; - $hit = 1 if $line =~ /\bstdio\.h/; - $hit = 1 if $line =~ /\bstdlib\.h/; - $hit = 1 if $line =~ /\bstring\.h/; - $hit = 1 if $line =~ /\btime\.h/ && $line !~ m!sys/time.h!; - next if !$hit; - print "$line\n"; - $names{$1} = 1 if $line =~ /^([^:]+)/; + foreach my $file (split /\n/, $files) { + next if $file =~ m!include/vltstd/vpi_user.h!; # IEEE Standard file - can't change it + next if $file =~ m!include/gtkwave/!; # Standard file - can't change it + my $filename = catfile($root, $file); + @lines = split /\n/, file_contents($filename); + @include_lines = grep(/include/, @lines); + foreach my $line (@include_lines) { + my $hit; + $hit = 1 if $line =~ /\bassert\.h/; + $hit = 1 if $line =~ /\bctype\.h/; + $hit = 1 if $line =~ /\berrno\.h/; + $hit = 1 if $line =~ /\bfloat\.h/; + $hit = 1 if $line =~ /\blimits\.h/; + $hit = 1 if $line =~ /\blocale\.h/; + $hit = 1 if $line =~ /\bmath\.h/; + $hit = 1 if $line =~ /\bsetjmp\.h/; + $hit = 1 if $line =~ /\bsignal\.h/; + $hit = 1 if $line =~ /\bstdarg\.h/; + $hit = 1 if $line =~ /\bstdbool\.h/; + $hit = 1 if $line =~ /\bstddef\.h/; + #Not yet: $hit = 1 if $line =~ /\bstdint\.h/; + $hit = 1 if $line =~ /\bstdio\.h/; + $hit = 1 if $line =~ /\bstdlib\.h/; + $hit = 1 if $line =~ /\bstring\.h/; + $hit = 1 if $line =~ /\btime\.h/ && $line !~ m!sys/time.h!; + next if !$hit; + $names{"$filename: $line"} = 1; + } } - if (keys %names) { - error("Files like stdint.h instead of cstdint: ", join(' ', sort keys %names)); + error("Files like stdint.h instead of cstdint:\n ", join("\n ", sort keys %names)); } } diff --git a/test_regress/t/t_dist_copyright.pl b/test_regress/t/t_dist_copyright.pl index e69ddb798..809b9af7b 100755 --- a/test_regress/t/t_dist_copyright.pl +++ b/test_regress/t/t_dist_copyright.pl @@ -57,14 +57,26 @@ my $Exempt_Files_List_Re = '^(' . join('|', (map { quotemeta $_ } @Exempt_Files_ if (!-r "$root/.git") { skip("Not in a git repository"); } else { - my $files = `cd $root && git ls-files --exclude-standard`; + my $out = `cd $root && git ls-files --exclude-standard`; my $year = strftime("%Y", localtime); - - $files =~ s/\s+/ /g; - foreach my $filename (split /\s+/, $files) { + my %files; + $out =~ s/\s+/ /g; + foreach my $filename (split /\s+/, $out) { next if $filename =~ /$Exempt_Files_Re/; next if $filename =~ /$Exempt_Files_List_Re/; + $files{$filename} = 1; + } + + my %added; + $out = `cd $root && git diff --name-status HEAD^^^^^`; + foreach my $line (split /\n/, $out) { + next if $line !~ /^A\s+(.*)/; + $added{$1} = 1; + } + + foreach my $filename (sort keys %files) { my $fh = IO::File->new("<$root/$filename") or error("$! $filename"); + next if !$fh; my $spdx; my $copyright; my $release; @@ -73,13 +85,13 @@ if (!-r "$root/.git") { $spdx = $line; } elsif ($line =~ /Copyright 20[0-9][0-9]/) { $copyright = $line; - if ($line !~ /Wilson Snyder|Geza Lore/ - && !($filename =~ /test_regress/ && $line =~ /Antmicro|Todd Strader/)) { + if ($line =~ /Wilson Snyder/) { + } elsif (!$added{$filename} && $line =~ /Antmicro|Geza Lore|Todd Strader/) { + } elsif ($filename =~ /$Exempt_Author_Re/) { + } else { my $yeardash = ($filename =~ m!test_regress/t!) ? $year : $year."-".$year; - if ($filename !~ /$Exempt_Author_Re/) { - warn " ".$copyright; - error("$filename: Please use standard 'Copyright $yeardash by Wilson Snyder'"); - } + warn " ".$copyright; + error("$filename: Please use standard 'Copyright $yeardash by Wilson Snyder'"); } } elsif ($line =~ m!Creative Commons Public Domain! || $line =~ m!freely copied and/or distributed! diff --git a/test_regress/t/t_dist_fixme.pl b/test_regress/t/t_dist_fixme.pl index 74c927883..0f36f4486 100755 --- a/test_regress/t/t_dist_fixme.pl +++ b/test_regress/t/t_dist_fixme.pl @@ -26,21 +26,11 @@ if (!-r "$root/.git") { $files =~ s/\s+/ /g; my @batch; my $n = 0; + my $re = qr/(FIX[M]E|BO[Z]O)/; foreach my $file (split /\s+/, $files) { - $batch[$n] .= $file . " "; - ++$n if (length($batch[$n]) > 10000); - } - - foreach my $bfiles (@batch) { - my $cmd = "cd $root && grep -n -P '(FIX" . "ME|BO" . "ZO)' $bfiles | sort"; - my $grep = `$cmd`; - if ($grep ne "") { - print "$grep\n"; - foreach my $line (split /\n/, $grep) { - print "L $line\n"; - # FIXMEV5 for use in develop-v5 branch until merged to master - $names{$1} = 1 if $line =~ /^([^:]+)/ && $line !~ /FIXMEV5/; - } + my $wholefile = file_contents($root . "/" . $file); + if ($wholefile =~ /$re/) { + $names{$file} = 1; } } if (scalar(%names) >= 1) { diff --git a/test_regress/t/t_dist_tabs.pl b/test_regress/t/t_dist_tabs.pl index 1f4a6b734..bc5f0c1a9 100755 --- a/test_regress/t/t_dist_tabs.pl +++ b/test_regress/t/t_dist_tabs.pl @@ -12,7 +12,8 @@ scenarios(dist => 1); my $root = ".."; -my $Tabs_Exempt_Re = qr!(\.out$)|(/gtkwave)|(Makefile)|(\.mk$)|(\.mk\.in$)|(nodist/fastcov.py)!; +my $Make_Style_Re = qr!(Makefile)|(\.mk$)|(\.mk\.in$)!; +my $Tabs_Exempt_Re = qr!(\.out$)|(/gtkwave)|(Makefile)|(\.mk$)|(\.mk\.in$)!; #my $Wide_Exempt_Re = qr!(\.l$)|(\.y$)!; my $Wide_Exempt_Re = qr!.*!; # clang-tidy generally cleans up @@ -31,10 +32,17 @@ if (!-r "$root/.git") { my $btab; my $lineno = 0; foreach my $line ((split /\n/, $diff), "+++ b/_the_end") { + $fline = $line; + $fline =~ s!^(\+)#\t!$1!; # special case, lines starting with #\t are OK in Makefiles if ($line =~ m!^\+\+\+ b/(.*)!) { + if ($file && !$astab && $bstab + && $file =~ $Make_Style_Re) { + $summary = "File modifications add new stray tabs (please untabify the patch):"; + $warns{$file} = "File modification adds new stray tabs (please untabify the patch): $file"; + } if ($file && !$atab && $btab && $file !~ $Tabs_Exempt_Re) { - $summary = "File modifications adds new tabs (please untabify the patch):"; + $summary = "File modifications add new tabs (please untabify the patch):"; $warns{$file} = "File modification adds new tabs (please untabify the patch): $file"; } # Next @@ -53,6 +61,14 @@ if (!-r "$root/.git") { $atab = 1; } } + elsif ($fline =~ m!^-.+[^\t]\t!) { + print " Had stray tabs\n" if $Self->{verbose} && !$astab; + $astab = 1; + } + elsif ($fline =~ m!^+.+[^\t]\t!) { + print " Inserts stray tabs\n" if $Self->{verbose} && !$bstab; + $bstab = 1; + } elsif ($line =~ m!^-.*\t!) { print " Had tabs\n" if $Self->{verbose} && !$atab; $atab = 1; diff --git a/test_regress/t/t_dist_warn_coverage.pl b/test_regress/t/t_dist_warn_coverage.pl index 258b74a8f..7fb44afc5 100755 --- a/test_regress/t/t_dist_warn_coverage.pl +++ b/test_regress/t/t_dist_warn_coverage.pl @@ -26,12 +26,12 @@ foreach my $s ( 'Enum names without values only allowed on numeric types', # Hard to hit 'Enum ranges must be integral, per spec', # Hard to hit 'Return with return value isn\'t underneath a function', # Hard to hit, get other bad return messages - 'Select from non-array ', # Instead get type does not have a bit range 'Syntax error parsing real: \'', # Instead can't lex the number 'Unsupported: Ranges ignored in port-lists', # Hard to hit 'dynamic new() not expected in this context (expected under an assign)', # Instead get syntax error # Not yet analyzed ' is not an in/out/inout/param/interface: ', + 'Big endian instance range connecting to ', ' loading non-variable', '--pipe-filter protocol error, unexpected: ', '/*verilator sformat*/ can only be applied to last argument of ', @@ -53,11 +53,9 @@ foreach my $s ( 'Exceeded limit of ', 'Extern declaration\'s scope is not a defined class', 'Format to $display-like function must have constant format string', - 'Forward typedef used as class/package does not resolve to class/package: ', 'Illegal +: or -: select; type already selected, or bad dimension: ', 'Illegal bit or array select; type already selected, or bad dimension: ', 'Illegal range select; type already selected, or bad dimension: ', - 'In defparam, instance ', 'Interface port ', 'Member selection of non-struct/union object \'', 'Modport item is not a function/task: ', diff --git a/test_regress/t/t_dos.v b/test_regress/t/t_dos.v old mode 100755 new mode 100644 diff --git a/test_regress/t/t_dpi_arg_inout_type.pl b/test_regress/t/t_dpi_arg_inout_type.pl index 9ca750797..3bab51d49 100755 --- a/test_regress/t/t_dpi_arg_inout_type.pl +++ b/test_regress/t/t_dpi_arg_inout_type.pl @@ -30,7 +30,7 @@ compile( ); if ($Self->{vlt_all}) { - files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + files_identical("$Self->{obj_dir}/$Self->{vm_prefix}__Dpi.h", "t/$Self->{name}__Dpi.out"); } diff --git a/test_regress/t/t_dpi_arg_inout_unpack.pl b/test_regress/t/t_dpi_arg_inout_unpack.pl index 18dfa90cf..f58b3fb94 100755 --- a/test_regress/t/t_dpi_arg_inout_unpack.pl +++ b/test_regress/t/t_dpi_arg_inout_unpack.pl @@ -30,7 +30,7 @@ compile( ); if ($Self->{vlt_all}) { - files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + files_identical("$Self->{obj_dir}/$Self->{vm_prefix}__Dpi.h", "t/$Self->{name}__Dpi.out"); } diff --git a/test_regress/t/t_dpi_arg_input_type.pl b/test_regress/t/t_dpi_arg_input_type.pl index 9ca750797..3bab51d49 100755 --- a/test_regress/t/t_dpi_arg_input_type.pl +++ b/test_regress/t/t_dpi_arg_input_type.pl @@ -30,7 +30,7 @@ compile( ); if ($Self->{vlt_all}) { - files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + files_identical("$Self->{obj_dir}/$Self->{vm_prefix}__Dpi.h", "t/$Self->{name}__Dpi.out"); } diff --git a/test_regress/t/t_dpi_arg_input_unpack.pl b/test_regress/t/t_dpi_arg_input_unpack.pl index 18dfa90cf..f58b3fb94 100755 --- a/test_regress/t/t_dpi_arg_input_unpack.pl +++ b/test_regress/t/t_dpi_arg_input_unpack.pl @@ -30,7 +30,7 @@ compile( ); if ($Self->{vlt_all}) { - files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + files_identical("$Self->{obj_dir}/$Self->{vm_prefix}__Dpi.h", "t/$Self->{name}__Dpi.out"); } diff --git a/test_regress/t/t_dpi_arg_output_type.pl b/test_regress/t/t_dpi_arg_output_type.pl index 9ca750797..3bab51d49 100755 --- a/test_regress/t/t_dpi_arg_output_type.pl +++ b/test_regress/t/t_dpi_arg_output_type.pl @@ -30,7 +30,7 @@ compile( ); if ($Self->{vlt_all}) { - files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + files_identical("$Self->{obj_dir}/$Self->{vm_prefix}__Dpi.h", "t/$Self->{name}__Dpi.out"); } diff --git a/test_regress/t/t_dpi_arg_output_unpack.pl b/test_regress/t/t_dpi_arg_output_unpack.pl index 18dfa90cf..f58b3fb94 100755 --- a/test_regress/t/t_dpi_arg_output_unpack.pl +++ b/test_regress/t/t_dpi_arg_output_unpack.pl @@ -30,7 +30,7 @@ compile( ); if ($Self->{vlt_all}) { - files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + files_identical("$Self->{obj_dir}/$Self->{vm_prefix}__Dpi.h", "t/$Self->{name}__Dpi.out"); } diff --git a/test_regress/t/t_dpi_result_type.pl b/test_regress/t/t_dpi_result_type.pl index 9ca750797..3bab51d49 100755 --- a/test_regress/t/t_dpi_result_type.pl +++ b/test_regress/t/t_dpi_result_type.pl @@ -30,7 +30,7 @@ compile( ); if ($Self->{vlt_all}) { - files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__Dpi.h", + files_identical("$Self->{obj_dir}/$Self->{vm_prefix}__Dpi.h", "t/$Self->{name}__Dpi.out"); } diff --git a/test_regress/t/t_dpi_unpack_bad.out b/test_regress/t/t_dpi_unpack_bad.out index 0c7aa4fec..aaaeef547 100644 --- a/test_regress/t/t_dpi_unpack_bad.out +++ b/test_regress/t/t_dpi_unpack_bad.out @@ -3,11 +3,11 @@ 21 | import_func0(sig0); | ^~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Warning-WIDTH: t/t_dpi_unpack_bad.v:21:7: Operator TASKREF 'import_func0' expects 4 bits on the Function Argument, but Function Argument's VARREF 'sig0' generates 3 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_dpi_unpack_bad.v:21:7: Operator TASKREF 'import_func0' expects 4 bits on the Function Argument, but Function Argument's VARREF 'sig0' generates 3 bits. + : ... In instance t 21 | import_func0(sig0); | ^~~~~~~~~~~~ - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:23:20: Shape of the argument does not match the shape of the parameter ('logic[2:0]$[0:2][0:1]' v.s. 'logic[2:0]$[0:2]') : ... In instance t 23 | import_func1(sig1); @@ -24,8 +24,8 @@ : ... In instance t 29 | import_func0(sig0[1]); | ^ -%Warning-WIDTH: t/t_dpi_unpack_bad.v:29:7: Operator TASKREF 'import_func0' expects 4 bits on the Function Argument, but Function Argument's ARRAYSEL generates 3 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_dpi_unpack_bad.v:29:7: Operator TASKREF 'import_func0' expects 4 bits on the Function Argument, but Function Argument's ARRAYSEL generates 3 bits. + : ... In instance t 29 | import_func0(sig0[1]); | ^~~~~~~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_dpi_var.pl b/test_regress/t/t_dpi_var.pl index f96ebbdda..85b491082 100755 --- a/test_regress/t/t_dpi_var.pl +++ b/test_regress/t/t_dpi_var.pl @@ -18,10 +18,10 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_dpi_var_vlt.pl b/test_regress/t/t_dpi_var_vlt.pl index 10c8d696f..bf71f4bf1 100755 --- a/test_regress/t/t_dpi_var_vlt.pl +++ b/test_regress/t/t_dpi_var_vlt.pl @@ -20,10 +20,10 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_dynarray_bad.out b/test_regress/t/t_dynarray_bad.out index af5fe4a48..a579f8fc8 100644 --- a/test_regress/t/t_dynarray_bad.out +++ b/test_regress/t/t_dynarray_bad.out @@ -1,9 +1,9 @@ -%Warning-WIDTH: t/t_dynarray_bad.v:15:11: Operator NEWDYNAMIC expects 32 bits on the new() size, but new() size's VARREF 's' generates 64 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_dynarray_bad.v:15:11: Operator NEWDYNAMIC expects 32 bits on the new() size, but new() size's VARREF 's' generates 64 bits. + : ... In instance t 15 | a = new [s]; | ^~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Internal Error: t/t_dynarray_bad.v:15:16: ../V3Number.cpp:#: Number operation called with non-logic (double or string) argument: '"str"" 15 | a = new [s]; | ^ diff --git a/test_regress/t/t_dynarray_init.pl b/test_regress/t/t_dynarray_init.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_dynarray_init.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_dynarray_init.v b/test_regress/t/t_dynarray_init.v new file mode 100644 index 000000000..756792b45 --- /dev/null +++ b/test_regress/t/t_dynarray_init.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) + +module t (/*AUTOARG*/); + + int a1[] = '{12, 13}; + int a2[] = {14, 15}; + int a3[] = '{16}; + int a4[] = {17}; + + initial begin + `checkh(a1.size, 2); + `checkh(a1[0], 12); + `checkh(a1[1], 13); + + `checkh(a2.size, 2); + `checkh(a2[0], 14); + `checkh(a2[1], 15); + + `checkh(a3.size, 1); + `checkh(a3[0], 16); + + `checkh(a4.size, 1); + `checkh(a4[0], 17); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_embed1.pl b/test_regress/t/t_embed1.pl index 85d36addd..5de7bb286 100755 --- a/test_regress/t/t_embed1.pl +++ b/test_regress/t/t_embed1.pl @@ -19,7 +19,7 @@ mkdir $child_dir; # Compile the child { my @cmdargs = $Self->compile_vlt_cmd - (VM_PREFIX => "$Self->{VM_PREFIX}_child", + (vm_prefix => "$Self->{vm_prefix}_child", top_filename => "$Self->{name}_child.v", verilator_flags => ["-cc", "-Mdir", "${child_dir}", "--debug-check"], # Can't use multi threading (like hier blocks), but needs to be thread safe @@ -34,7 +34,7 @@ mkdir $child_dir; $ENV{MAKE}, "-f" . getcwd() . "/Makefile_obj", "CPPFLAGS_DRIVER=-D" . uc($self->{name}), ($opt_verbose ? "CPPFLAGS_DRIVER2=-DTEST_VERBOSE=1" : ""), - "VM_PREFIX=$self->{VM_PREFIX}_child", + "VM_PREFIX=$self->{vm_prefix}_child", "V$self->{name}_child__ALL.a", # bypass default rule, make archive ($param{make_flags}||""), ]); diff --git a/test_regress/t/t_emit_memb_limit.pl b/test_regress/t/t_emit_memb_limit.pl index 21d001dd2..39e3eb212 100755 --- a/test_regress/t/t_emit_memb_limit.pl +++ b/test_regress/t/t_emit_memb_limit.pl @@ -55,7 +55,7 @@ execute( check_finished => 1, ); -file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root.h", qr/struct \{/); +file_grep("$Self->{obj_dir}/$Self->{vm_prefix}___024root.h", qr/struct \{/); ok(1); 1; diff --git a/test_regress/t/t_enum_bad_value.out b/test_regress/t/t_enum_bad_value.out new file mode 100644 index 000000000..052f16ac8 --- /dev/null +++ b/test_regress/t/t_enum_bad_value.out @@ -0,0 +1,5 @@ +%Error: t/t_enum_bad_value.v:10:19: Enum value exceeds width of enum type (IEEE 1800-2017 6.19) + : ... In instance t + 10 | VALUE_BAD = 8 + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_enum_bad_value.pl b/test_regress/t/t_enum_bad_value.pl new file mode 100755 index 000000000..0a723255a --- /dev/null +++ b/test_regress/t/t_enum_bad_value.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + verilator_flags2 => ["--Wno-fatal"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_enum_bad_value.v b/test_regress/t/t_enum_bad_value.v new file mode 100644 index 000000000..ed97f82a0 --- /dev/null +++ b/test_regress/t/t_enum_bad_value.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(); + + typedef enum [2:0] { + VALUE_BAD = 8 + } enum_t; + +endmodule diff --git a/test_regress/t/t_enum_const_methods.pl b/test_regress/t/t_enum_const_methods.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_enum_const_methods.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_enum_const_methods.v b/test_regress/t/t_enum_const_methods.v new file mode 100644 index 000000000..e5ce9e979 --- /dev/null +++ b/test_regress/t/t_enum_const_methods.v @@ -0,0 +1,47 @@ +// DESCRIPTION: Verilator: constant enum methods +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2022 by Todd Strader +// SPDX-License-Identifier: CC0-1.0 + +module t (); + + typedef enum [1:0] {E0, E1, E2} enm_t; + + function automatic enm_t get_first(); + enm_t enm; + return enm.first; + endfunction + + localparam enm_t enum_first = get_first(); + + function automatic enm_t get_last(); + enm_t enm; + return enm.last; + endfunction + + localparam enm_t enum_last = get_last(); + + function automatic enm_t get_second(); + enm_t enm; + enm = enm.first; + return enm.next; + endfunction + + localparam enm_t enum_second = get_second(); + + function automatic string get_name(enm_t enm); + return enm.name; + endfunction + + localparam string e0_name = get_name(E0); + + initial begin + if (enum_first != E0) $stop; + if (enum_last != E2) $stop; + if (enum_second != E1) $stop; + if (e0_name != "E0") $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_enum_huge_methods.v b/test_regress/t/t_enum_huge_methods.v index 3fd9eb1d6..951c57d1b 100644 --- a/test_regress/t/t_enum_huge_methods.v +++ b/test_regress/t/t_enum_huge_methods.v @@ -34,12 +34,16 @@ module t (/*AUTOARG*/ else if (cyc == 1) begin `checks(e.name, "E01"); `checkh(e.next, ELARGE); + `checkh(e.next(0), E01); + `checkh(e.prev(0), E01); e <= ELARGE; end else if (cyc == 3) begin `checks(e.name, "ELARGE"); `checkh(e.next, E01); `checkh(e.prev, E01); + `checkh(e.next(0), ELARGE); + `checkh(e.prev(0), ELARGE); e <= E01; end // diff --git a/test_regress/t/t_enum_public.cpp b/test_regress/t/t_enum_public.cpp index 7bd7c99d5..8dd9f8931 100644 --- a/test_regress/t/t_enum_public.cpp +++ b/test_regress/t/t_enum_public.cpp @@ -18,7 +18,7 @@ int main(int argc, char* argv[]) { Verilated::debug(0); Verilated::commandArgs(argc, argv); - Vt_enum_public* topp = new Vt_enum_public; + VM_PREFIX* topp = new VM_PREFIX; // Make sure public tag worked if (Vt_enum_public_p3::ZERO == Vt_enum_public_p3::ONE) {} diff --git a/test_regress/t/t_event_control_expr.pl b/test_regress/t/t_event_control_expr.pl index a50ea7293..133221d43 100755 --- a/test_regress/t/t_event_control_expr.pl +++ b/test_regress/t/t_event_control_expr.pl @@ -19,7 +19,7 @@ execute( check_finished => 1, ); -for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp")) { +for my $file (glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.cpp")) { # Check that these simple expressions are not stored in temp variables file_grep_not($file, qr/__Vtrigcurr__expression_.* = vlSelf->clk;/); file_grep_not($file, qr/__Vtrigcurr__expression_.* = vlSelf->t__DOT__q.at\(0U\);/); diff --git a/test_regress/t/t_event_control_star.out b/test_regress/t/t_event_control_star.out new file mode 100644 index 000000000..c8682b945 --- /dev/null +++ b/test_regress/t/t_event_control_star.out @@ -0,0 +1,6 @@ +%Error-UNSUPPORTED: t/t_event_control_star.v:19:14: Unsupported: no sense equation (@*) + 19 | @* a = c; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Verilator internal fault, sorry. Suggest trying --debug --gdbbt +%Error: Command Failed diff --git a/test_regress/t/t_event_control_star.pl b/test_regress/t/t_event_control_star.pl new file mode 100755 index 000000000..c5e251fe7 --- /dev/null +++ b/test_regress/t/t_event_control_star.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["--timing"], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_event_control_star.v b/test_regress/t/t_event_control_star.v new file mode 100644 index 000000000..7df4ae1d0 --- /dev/null +++ b/test_regress/t/t_event_control_star.v @@ -0,0 +1,39 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Based on ivtest's nested_impl_event1.v by Martin Whitaker. + +module t(); + + reg a; + reg b; + reg c; + + always @* begin // @(b or c) + a = b; + $display("[%0t] Triggered 1 @(b or c)", $time); + + @* a = c; // @(c) + $display("[%0t] Triggered 2 @(c)", $time); + end + + initial begin + #10; + b = 0; + #10; + b = 1; + #10; + c = 0; + #10; + c = 1; + #10; + c = 0; + #10; + $write("*-* All Finished *-*\n"); + $finish(0); + end + +endmodule diff --git a/test_regress/t/t_expr_incr_unsup.out b/test_regress/t/t_expr_incr_unsup.out new file mode 100644 index 000000000..6f899d2ac --- /dev/null +++ b/test_regress/t/t_expr_incr_unsup.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_expr_incr_unsup.v:17:34: Unsupported: Inc/Dec of expression with side-effects + 17 | $display("Value: %d", arr[postincrement_i()]++); + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_expr_incr_unsup.pl b/test_regress/t/t_expr_incr_unsup.pl new file mode 100755 index 000000000..35d749208 --- /dev/null +++ b/test_regress/t/t_expr_incr_unsup.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_expr_incr_unsup.v b/test_regress/t/t_expr_incr_unsup.v new file mode 100644 index 000000000..9d6647cbf --- /dev/null +++ b/test_regress/t/t_expr_incr_unsup.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 Krzysztof Boronski. +// SPDX-License-Identifier: CC0-1.0 + +int i = 0; + +function int postincrement_i; + return i++; +endfunction + +module t; + initial begin + int arr [1:0] = {0, 0}; + i = 0; + $display("Value: %d", arr[postincrement_i()]++); + end +endmodule diff --git a/test_regress/t/t_extract_static_const.v b/test_regress/t/t_extract_static_const.v old mode 100755 new mode 100644 diff --git a/test_regress/t/t_extract_static_const_multimodule.v b/test_regress/t/t_extract_static_const_multimodule.v old mode 100755 new mode 100644 diff --git a/test_regress/t/t_flag_build_dep_bin.pl b/test_regress/t/t_flag_build_dep_bin.pl index 13eaa6fe3..95eda3687 100755 --- a/test_regress/t/t_flag_build_dep_bin.pl +++ b/test_regress/t/t_flag_build_dep_bin.pl @@ -14,7 +14,7 @@ compile( v_flags2 => ['--build-dep-bin', 'path_to_exe'], ); -file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}__ver.d", qr/path_to_exe/); +file_grep("$Self->{obj_dir}/$Self->{vm_prefix}__ver.d", qr/path_to_exe/); ok(1); 1; diff --git a/test_regress/t/t_flag_comp_limit_parens.pl b/test_regress/t/t_flag_comp_limit_parens.pl index d978e33fa..444c84256 100755 --- a/test_regress/t/t_flag_comp_limit_parens.pl +++ b/test_regress/t/t_flag_comp_limit_parens.pl @@ -18,7 +18,7 @@ execute( check_finished => 1, ); -my @files = glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__DepSet*__Slow.cpp"); +my @files = glob_all("$Self->{obj_dir}/$Self->{vm_prefix}___024root__DepSet*__Slow.cpp"); file_grep_any(\@files, qr/Vdeeptemp/i); ok(1); diff --git a/test_regress/t/t_flag_context_bad.out b/test_regress/t/t_flag_context_bad.out index 13052d8dd..5cd7f81be 100644 --- a/test_regress/t/t_flag_context_bad.out +++ b/test_regress/t/t_flag_context_bad.out @@ -1,7 +1,7 @@ -%Warning-WIDTH: t/t_flag_context_bad.v:9:19: Operator ASSIGNW expects 3 bits on the Assign RHS, but Assign RHS's CONST '5'h1f' generates 5 bits. - : ... In instance t - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. +%Warning-WIDTHTRUNC: t/t_flag_context_bad.v:9:19: Operator ASSIGNW expects 3 bits on the Assign RHS, but Assign RHS's CONST '5'h1f' generates 5 bits. + : ... In instance t + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Warning-UNUSEDSIGNAL: t/t_flag_context_bad.v:9:15: Signal is not used: 'foo' : ... In instance t %Error: Exiting due to diff --git a/test_regress/t/t_flag_csplit.pl b/test_regress/t/t_flag_csplit.pl index f4634a9e5..1eb2c8dd4 100755 --- a/test_regress/t/t_flag_csplit.pl +++ b/test_regress/t/t_flag_csplit.pl @@ -30,9 +30,9 @@ while (1) { tee => $self->{verbose}, cmd=>[$ENV{MAKE}, "-C " . $Self->{obj_dir}, - "-f $Self->{VM_PREFIX}.mk", + "-f $Self->{vm_prefix}.mk", "-j 4", - "VM_PREFIX=$Self->{VM_PREFIX}", + "VM_PREFIX=$Self->{vm_prefix}", "TEST_OBJ_DIR=$Self->{obj_dir}", "CPPFLAGS_DRIVER=-D".uc($Self->{name}), ($opt_verbose ? "CPPFLAGS_DRIVER2=-DTEST_VERBOSE=1" : ""), @@ -47,7 +47,7 @@ while (1) { ); # Splitting should set VM_PARALLEL_BUILDS to 1 by default - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}_classes.mk", qr/VM_PARALLEL_BUILDS\s*=\s*1/); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}_classes.mk", qr/VM_PARALLEL_BUILDS\s*=\s*1/); check_splits(); check_no_all_file(); check_gcc_flags("$Self->{obj_dir}/vlt_gcc.log"); @@ -113,7 +113,7 @@ sub check_gcc_flags { while (defined(my $line = $fh->getline)) { chomp $line; print ":log: $line\n" if $Self->{verbose}; - if ($line =~ /$Self->{VM_PREFIX}\S*\.cpp/) { + if ($line =~ /$Self->{vm_prefix}\S*\.cpp/) { my $filetype = ($line =~ /Slow|Syms/) ? "slow" : "fast"; my $opt = ($line !~ /-O2/) ? "slow" : "fast"; print "$filetype, $opt, $line\n" if $Self->{verbose}; diff --git a/test_regress/t/t_flag_csplit_off.pl b/test_regress/t/t_flag_csplit_off.pl index ae9edfc29..64d8e466a 100755 --- a/test_regress/t/t_flag_csplit_off.pl +++ b/test_regress/t/t_flag_csplit_off.pl @@ -32,9 +32,9 @@ while (1) { tee => $self->{verbose}, cmd=>[$ENV{MAKE}, "-C " . $Self->{obj_dir}, - "-f $Self->{VM_PREFIX}.mk", + "-f $Self->{vm_prefix}.mk", "-j 4", - "VM_PREFIX=$Self->{VM_PREFIX}", + "VM_PREFIX=$Self->{vm_prefix}", "TEST_OBJ_DIR=$Self->{obj_dir}", "CPPFLAGS_DRIVER=-D".uc($Self->{name}), ($opt_verbose ? "CPPFLAGS_DRIVER2=-DTEST_VERBOSE=1" : ""), @@ -48,7 +48,7 @@ while (1) { ); # Never spliting, so should set VM_PARALLEL_BUILDS to 0 by default - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}_classes.mk", qr/VM_PARALLEL_BUILDS\s*=\s*0/); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}_classes.mk", qr/VM_PARALLEL_BUILDS\s*=\s*0/); check_no_splits(); check_all_file(); check_gcc_flags("$Self->{obj_dir}/vlt_gcc.log"); diff --git a/test_regress/t/t_flag_ldflags.pl b/test_regress/t/t_flag_ldflags.pl index d72594ba4..8f5aa8958 100755 --- a/test_regress/t/t_flag_ldflags.pl +++ b/test_regress/t/t_flag_ldflags.pl @@ -35,11 +35,11 @@ compile( if ($^O eq "darwin") { run(cmd => ["cd $Self->{obj_dir}" . " && install_name_tool -add_rpath \@executable_path/." - . " $Self->{VM_PREFIX}"], + . " $Self->{vm_prefix}"], check_finished => 0); run(cmd => ["cd $Self->{obj_dir}" . " && install_name_tool -change t_flag_ldflags_so.so" - . " \@rpath/t_flag_ldflags_so.so $Self->{VM_PREFIX}"], + . " \@rpath/t_flag_ldflags_so.so $Self->{vm_prefix}"], check_finished => 0); } diff --git a/test_regress/t/t_flag_noop_bad.out b/test_regress/t/t_flag_noop_bad.out index d7bd1b71c..74b28bf7a 100644 --- a/test_regress/t/t_flag_noop_bad.out +++ b/test_regress/t/t_flag_noop_bad.out @@ -1 +1 @@ -%Error: verilator: Need --binary, --cc, --sc, --cdc, --dpi-hdr-only, --lint-only, --xml-only or --E option +%Error: verilator: Need --binary, --cc, --sc, --dpi-hdr-only, --lint-only, --xml-only or --E option diff --git a/test_regress/t/t_flag_prefix.v b/test_regress/t/t_flag_prefix.v old mode 100755 new mode 100644 diff --git a/test_regress/t/t_flag_structs_packed_bad.out b/test_regress/t/t_flag_structs_packed_bad.out index 3ca15d47c..43068e836 100644 --- a/test_regress/t/t_flag_structs_packed_bad.out +++ b/test_regress/t/t_flag_structs_packed_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_flag_structs_packed.v:14:19: Unpacked data type in packed struct/union (IEEE 1800-2017 7.2.1) +%Error: t/t_flag_structs_packed.v:14:19: Unpacked data type 'STRUCTDTYPE 'x.notpacked_t'' in packed struct/union (IEEE 1800-2017 7.2.1) : ... In instance x 14 | notpacked_t b; | ^ diff --git a/test_regress/t/t_flag_verilate_threads_bad.out b/test_regress/t/t_flag_verilate_threads_bad.out new file mode 100644 index 000000000..f26bfdd19 --- /dev/null +++ b/test_regress/t/t_flag_verilate_threads_bad.out @@ -0,0 +1,2 @@ +%Error: --verilate-jobs requires a non-negative integer, but '-1' was passed +%Error: Exiting due to diff --git a/test_regress/t/t_flag_verilate_threads_bad.pl b/test_regress/t/t_flag_verilate_threads_bad.pl new file mode 100755 index 000000000..8743294da --- /dev/null +++ b/test_regress/t/t_flag_verilate_threads_bad.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_flag_werror.v"); + +lint( + fails => 1, + verilator_flags => [qw(--verilate-jobs -1)], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_flag_werror_bad1.out b/test_regress/t/t_flag_werror_bad1.out index 844fdafb0..5e0131123 100644 --- a/test_regress/t/t_flag_werror_bad1.out +++ b/test_regress/t/t_flag_werror_bad1.out @@ -1,7 +1,7 @@ -%Warning-WIDTH: t/t_flag_werror.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_flag_werror.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. + : ... In instance t 10 | wire [3:0] foo = 6'h2e; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_flag_werror_bad2.out b/test_regress/t/t_flag_werror_bad2.out index 169d7bcc5..2f1001fbd 100644 --- a/test_regress/t/t_flag_werror_bad2.out +++ b/test_regress/t/t_flag_werror_bad2.out @@ -1,6 +1,6 @@ -%Error-WIDTH: t/t_flag_werror.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. - : ... In instance t +%Error-WIDTHTRUNC: t/t_flag_werror.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. + : ... In instance t 10 | wire [3:0] foo = 6'h2e; | ^ - ... For error description see https://verilator.org/warn/WIDTH?v=latest + ... For error description see https://verilator.org/warn/WIDTHTRUNC?v=latest %Error: Exiting due to diff --git a/test_regress/t/t_flag_wfatal.out b/test_regress/t/t_flag_wfatal.out index 6ce45b931..8489b1824 100644 --- a/test_regress/t/t_flag_wfatal.out +++ b/test_regress/t/t_flag_wfatal.out @@ -1,6 +1,6 @@ -%Warning-WIDTH: t/t_flag_wfatal.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_flag_wfatal.v:10:19: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS's CONST '6'h2e' generates 6 bits. + : ... In instance t 10 | wire [3:0] foo = 6'h2e; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. diff --git a/test_regress/t/t_flag_xinitial_0.pl b/test_regress/t/t_flag_xinitial_0.pl index 167593271..937f65c98 100755 --- a/test_regress/t/t_flag_xinitial_0.pl +++ b/test_regress/t/t_flag_xinitial_0.pl @@ -18,7 +18,7 @@ execute( check_finished => 1, ); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__Slow.cpp", qr/VL_RAND_RESET/); +file_grep_not("$Self->{obj_dir}/$Self->{vm_prefix}___024root__Slow.cpp", qr/VL_RAND_RESET/); ok(1); 1; diff --git a/test_regress/t/t_flag_xinitial_unique.pl b/test_regress/t/t_flag_xinitial_unique.pl index 3f6077c00..961fb9756 100755 --- a/test_regress/t/t_flag_xinitial_unique.pl +++ b/test_regress/t/t_flag_xinitial_unique.pl @@ -18,7 +18,7 @@ execute( check_finished => 1, ); -my @files = glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__DepSet_*__Slow.cpp"); +my @files = glob_all("$Self->{obj_dir}/$Self->{vm_prefix}___024root__DepSet_*__Slow.cpp"); file_grep_any(\@files, qr/VL_RAND_RESET/); ok(1); diff --git a/test_regress/t/t_force.v b/test_regress/t/t_force.v index d669a8d74..ec076fe3d 100644 --- a/test_regress/t/t_force.v +++ b/test_regress/t/t_force.v @@ -6,6 +6,7 @@ `define stop $stop `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) +`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); module t(/*AUTOARG*/ // Inputs @@ -21,6 +22,8 @@ module t(/*AUTOARG*/ int never_driven; int never_forced; + real r; + task force_bus; force bus[1:0] = 2'b10; endtask @@ -95,6 +98,25 @@ module t(/*AUTOARG*/ `checkh(bus, 4'b0101); end // + else if (cyc == 40) begin + r <= 1.25; + end + else if (cyc == 41) begin + `checkr(r, 1.25); + end + else if (cyc == 42) begin + force r = 2.5; + end + else if (cyc == 43) begin + `checkr(r, 2.5); + end + else if (cyc == 44) begin + release r; + end + else if (cyc == 45) begin + `checkr(r, 1.25); + end + // else if (cyc == 99) begin $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_force_release_net_trace.out b/test_regress/t/t_force_release_net_trace.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_force_release_var_trace.out b/test_regress/t/t_force_release_var_trace.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_foreach.pl b/test_regress/t/t_foreach.pl index 3ff192bbd..6a69d589f 100755 --- a/test_regress/t/t_foreach.pl +++ b/test_regress/t/t_foreach.pl @@ -20,14 +20,14 @@ execute( # We expect all loops should be unrolled by verilator, # none of the loop variables should exist in the output: -for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp")) { +for my $file (glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.cpp")) { file_grep_not($file, qr/index_/); } # Further, we expect that all logic within the loop should # have been evaluated inside the compiler. So there should be # no references to 'sum' in the .cpp. -for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp")) { +for my $file (glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.cpp")) { file_grep_not($file, qr/[^a-zA-Z]sum[^a-zA-Z]/); } diff --git a/test_regress/t/t_func.v b/test_regress/t/t_func.v index eb59f633f..7f9817703 100644 --- a/test_regress/t/t_func.v +++ b/test_regress/t/t_func.v @@ -9,6 +9,7 @@ module t; reg [31:0] rglobal; reg [31:0] vec [1:0]; reg [31:0] n; + int abcd; initial begin rglobal = 1; @@ -61,6 +62,12 @@ module t; if (rglobal !== 32'h9) $stop; // verilator lint_on IGNOREDRETURN + abcd = 0; + set_1_to_abcd; + if (abcd != 1) $stop; + set_2_to_abcd; + if (abcd != 2) $stop; + $write("*-* All Finished *-*\n"); $finish; end @@ -153,4 +160,12 @@ module t; return rglobal; endfunction + function void set_1_to_abcd; + abcd = 1; + endfunction + + task set_2_to_abcd; + abcd = 2; + endtask + endmodule diff --git a/test_regress/t/t_func_bad_width.out b/test_regress/t/t_func_bad_width.out index 03b1ee7dd..af48783fa 100644 --- a/test_regress/t/t_func_bad_width.out +++ b/test_regress/t/t_func_bad_width.out @@ -1,11 +1,11 @@ -%Warning-WIDTH: t/t_func_bad_width.v:13:13: Operator FUNCREF 'MUX' expects 40 bits on the Function Argument, but Function Argument's VARREF 'in' generates 39 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_func_bad_width.v:13:13: Operator FUNCREF 'MUX' expects 40 bits on the Function Argument, but Function Argument's VARREF 'in' generates 39 bits. + : ... In instance t 13 | out = MUX (in); | ^~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. -%Warning-WIDTH: t/t_func_bad_width.v:13:11: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's FUNCREF 'MUX' generates 32 bits. - : ... In instance t + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. +%Warning-WIDTHTRUNC: t/t_func_bad_width.v:13:11: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's FUNCREF 'MUX' generates 32 bits. + : ... In instance t 13 | out = MUX (in); | ^ %Error: Exiting due to diff --git a/test_regress/t/t_func_check.v b/test_regress/t/t_func_check.v index c35a17347..9163d9406 100644 --- a/test_regress/t/t_func_check.v +++ b/test_regress/t/t_func_check.v @@ -56,7 +56,7 @@ module chk (input clk, input rst_l, input expr); wire noxs = ((expr ^ expr) == 1'b0); - // FIXMEV5: this test is dodgy, noxs can be proven constant, so this block + // TODO: this test is dodgy, noxs can be proven constant, so this block // should never relly trigger... reg hasx; always @ (noxs) begin diff --git a/test_regress/t/t_func_dotted_inl0.pl b/test_regress/t/t_func_dotted_inl0.pl index f286aa790..62d4078a8 100755 --- a/test_regress/t/t_func_dotted_inl0.pl +++ b/test_regress/t/t_func_dotted_inl0.pl @@ -18,10 +18,10 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_func_dotted_inl0_vlt.pl b/test_regress/t/t_func_dotted_inl0_vlt.pl index 711fb0708..403177acf 100755 --- a/test_regress/t/t_func_dotted_inl0_vlt.pl +++ b/test_regress/t/t_func_dotted_inl0_vlt.pl @@ -18,10 +18,10 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_func_dotted_inl2.pl b/test_regress/t/t_func_dotted_inl2.pl index 2dede96b9..4e61437e7 100755 --- a/test_regress/t/t_func_dotted_inl2.pl +++ b/test_regress/t/t_func_dotted_inl2.pl @@ -18,8 +18,8 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_func_dotted_inl2_vlt.pl b/test_regress/t/t_func_dotted_inl2_vlt.pl index 5e8ee23b4..2d58fd95d 100755 --- a/test_regress/t/t_func_dotted_inl2_vlt.pl +++ b/test_regress/t/t_func_dotted_inl2_vlt.pl @@ -18,8 +18,8 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_func_no_parentheses_bad.out b/test_regress/t/t_func_no_parentheses_bad.out new file mode 100644 index 000000000..e5c42c647 --- /dev/null +++ b/test_regress/t/t_func_no_parentheses_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_func_no_parentheses_bad.v:21:11: Found definition of 'func' as a FUNC but expected a variable + 21 | a = func; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_func_no_parentheses_bad.pl b/test_regress/t/t_func_no_parentheses_bad.pl new file mode 100755 index 000000000..bd07fc421 --- /dev/null +++ b/test_regress/t/t_func_no_parentheses_bad.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_func_no_parentheses_bad.v b/test_regress/t/t_func_no_parentheses_bad.v new file mode 100644 index 000000000..a23810fdf --- /dev/null +++ b/test_regress/t/t_func_no_parentheses_bad.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +function static int func(); + int cnt = 0; + return ++cnt; +endfunction + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int a; + initial begin + a = func; + $stop; + end + +endmodule diff --git a/test_regress/t/t_func_noinl.v b/test_regress/t/t_func_noinl.v index 5631f30ab..2b280291b 100644 --- a/test_regress/t/t_func_noinl.v +++ b/test_regress/t/t_func_noinl.v @@ -76,7 +76,7 @@ module Test (/*AUTOARG*/ input [31:0] inp; output [31:0] outp; - function [31:0] no_inline_function; + function automatic [31:0] no_inline_function; input [31:0] var1; input [31:0] var2; /*verilator no_inline_task*/ diff --git a/test_regress/t/t_func_rand.cpp b/test_regress/t/t_func_rand.cpp index fdfaba95e..772dd9fee 100644 --- a/test_regress/t/t_func_rand.cpp +++ b/test_regress/t/t_func_rand.cpp @@ -16,7 +16,7 @@ int main(int argc, char* argv[]) { Verilated::debug(0); Verilated::commandArgs(argc, argv); - Vt_func_rand* topp = new Vt_func_rand; + VM_PREFIX* topp = new VM_PREFIX; printf("\nTesting\n"); for (int i = 0; i < 10; i++) { diff --git a/test_regress/t/t_func_tasknsvar_bad.out b/test_regress/t/t_func_tasknsvar_bad.out index 230364bae..d4c3ed0ed 100644 --- a/test_regress/t/t_func_tasknsvar_bad.out +++ b/test_regress/t/t_func_tasknsvar_bad.out @@ -2,7 +2,7 @@ 16 | foo(bus_we_select_from[2]); | ^ ... For error description see https://verilator.org/warn/TASKNSVAR?v=latest -%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:66 +%Error: Internal Error: t/t_func_tasknsvar_bad.v:10:7: ../V3Broken.cpp:#: Broken link in node (or something without maybePointedTo): 'm_varp && !m_varp->brokeExists()' @ ../V3AstNodes.cpp:72 10 | sig = '1; | ^~~ ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_fuzz_genintf_bad.out b/test_regress/t/t_fuzz_genintf_bad.out index 407d8e478..780ca81cb 100644 --- a/test_regress/t/t_fuzz_genintf_bad.out +++ b/test_regress/t/t_fuzz_genintf_bad.out @@ -1,10 +1,4 @@ -%Error-UNSUPPORTED: t/t_fuzz_genintf_bad.v:24:12: Unsupported: Member call on object 'VARREF 'j'' which is a 'BASICDTYPE 'integer'' - : ... In instance t - 24 | j.e(0), - | ^ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Internal Error: t/t_fuzz_genintf_bad.v:24:11: ../V3Width.cpp:#: Unlinked pin data type - : ... In instance t +%Error: t/t_fuzz_genintf_bad.v:24:11: Mixing positional and .*/named instantiation connection (IEEE 1800-2017 23.3.2) 24 | j.e(0), | ^ - ... See the manual at https://verilator.org/verilator_doc.html for more assistance. +%Error: Exiting due to diff --git a/test_regress/t/t_fuzz_negwidth_bad.out b/test_regress/t/t_fuzz_negwidth_bad.out index 7d1d69a9f..f6ee9cd4d 100644 --- a/test_regress/t/t_fuzz_negwidth_bad.out +++ b/test_regress/t/t_fuzz_negwidth_bad.out @@ -1,4 +1,16 @@ %Error: t/t_fuzz_negwidth_bad.v:9:9: Unsupported: Width of number exceeds implementation limit: 1231232312312312'd1 (IEEE 1800-2017 6.9.1) 9 | int c = 1231232312312312'd1; | ^~~~~~~~~~~~~~~~~~~ +%Error: t/t_fuzz_negwidth_bad.v:10:9: Syntax error: size cannot be provided with '0/'1/'x/'z: 12'1 (IEEE 1800-2017 5.7.1) + 10 | int e = 12'1; + | ^~~~ +%Error: t/t_fuzz_negwidth_bad.v:11:9: Syntax error: size cannot be provided with '0/'1/'x/'z: 12'0 (IEEE 1800-2017 5.7.1) + 11 | int f = 12'0; + | ^~~~ +%Error: t/t_fuzz_negwidth_bad.v:12:9: Syntax error: size cannot be provided with '0/'1/'x/'z: 12'z (IEEE 1800-2017 5.7.1) + 12 | int g = 12'z; + | ^~~~ +%Error: t/t_fuzz_negwidth_bad.v:13:9: Syntax error: size cannot be provided with '0/'1/'x/'z: 12'x (IEEE 1800-2017 5.7.1) + 13 | int h = 12'x; + | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_fuzz_negwidth_bad.v b/test_regress/t/t_fuzz_negwidth_bad.v index d9c7d3cdb..242f0a64b 100644 --- a/test_regress/t/t_fuzz_negwidth_bad.v +++ b/test_regress/t/t_fuzz_negwidth_bad.v @@ -7,3 +7,7 @@ int a = -12'd1; int b = 65536'd1; int c = 1231232312312312'd1; +int e = 12'1; +int f = 12'0; +int g = 12'z; +int h = 12'x; diff --git a/test_regress/t/t_gantt_two.cpp b/test_regress/t/t_gantt_two.cpp index 7b1375126..9bea82889 100644 --- a/test_regress/t/t_gantt_two.cpp +++ b/test_regress/t/t_gantt_two.cpp @@ -21,8 +21,8 @@ int main(int argc, char** argv) { contextp->debug(0); contextp->commandArgs(argc, argv); - std::unique_ptr topap{new Vt_gantt_two{contextp.get(), "topa"}}; - std::unique_ptr topbp{new Vt_gantt_two{contextp.get(), "topb"}}; + std::unique_ptr topap{new VM_PREFIX{contextp.get(), "topa"}}; + std::unique_ptr topbp{new VM_PREFIX{contextp.get(), "topb"}}; topap->clk = false; topap->eval(); diff --git a/test_regress/t/t_gate_basic.v b/test_regress/t/t_gate_basic.v index 9a3e7fbab..326a23347 100644 --- a/test_regress/t/t_gate_basic.v +++ b/test_regress/t/t_gate_basic.v @@ -15,9 +15,10 @@ module t (/*AUTOARG*/ reg [31:0] a; reg [31:0] b; - wire [2:0] bf; buf BF0 (bf[0], a[0]), - BF1 (bf[1], a[1]), - BF2 (bf[2], a[2]); + wire [2:0] bf; + buf BF0 (bf[0], a[0]), + BF1 (bf[1], a[1]), + BF2 (bf[2], a[2]); // verilator lint_off IMPLICIT not #(0.108) NT0 (nt0, a[0]); @@ -29,6 +30,11 @@ module t (/*AUTOARG*/ xnor (xn0, a[0], b[0], b[2]); // verilator lint_on IMPLICIT + wire [2:0] bfm; + buf BFM (bfm[0], bfm[1], bfm[2], a[0]); + wire [2:0] ntm; + not NTM (ntm[0], ntm[1], ntm[2], a[0]); + parameter BITS=32; wire [BITS-1:0] ba; buf BARRAY [BITS-1:0] (ba, a); @@ -85,6 +91,8 @@ module t (/*AUTOARG*/ a <= 32'h529ab56f; b <= 32'h7835a237; if (bf !== 3'b100) $stop; + if (bfm != 3'b000) $stop; + if (ntm != 3'b111) $stop; if (nt0 !== 1'b1) $stop; if (an0 !== 1'b0) $stop; if (nd0 !== 1'b1) $stop; @@ -96,6 +104,8 @@ module t (/*AUTOARG*/ end if (cyc==3) begin if (bf !== 3'b111) $stop; + if (bfm != 3'b111) $stop; + if (ntm != 3'b000) $stop; if (nt0 !== 1'b0) $stop; if (an0 !== 1'b1) $stop; if (nd0 !== 1'b0) $stop; diff --git a/test_regress/t/t_gate_delay_unsup.out b/test_regress/t/t_gate_delay_unsup.out index c3e3e70fd..24b698bab 100644 --- a/test_regress/t/t_gate_delay_unsup.out +++ b/test_regress/t/t_gate_delay_unsup.out @@ -1,5 +1,5 @@ -%Warning-RISEFALLDLY: t/t_gate_basic.v:25:12: Unsupported: rising/falling/turn-off delays. Using the first delay - 25 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]); +%Warning-RISEFALLDLY: t/t_gate_basic.v:26:12: Unsupported: rising/falling/turn-off delays. Using the first delay + 26 | nand #(2,3) ND0 (nd0, a[0], b[0], b[1]); | ^ ... For warning description see https://verilator.org/warn/RISEFALLDLY?v=latest ... Use "/* verilator lint_off RISEFALLDLY */" and lint_on around source to disable this message. diff --git a/test_regress/t/t_gate_ormux.v b/test_regress/t/t_gate_ormux.v old mode 100755 new mode 100644 diff --git a/test_regress/t/t_gen_defparam_nfound_bad.out b/test_regress/t/t_gen_defparam_nfound_bad.out new file mode 100644 index 000000000..b66fe1bd3 --- /dev/null +++ b/test_regress/t/t_gen_defparam_nfound_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_gen_defparam_nfound_bad.v:9:17: In defparam, instance z never declared + 9 | defparam z.W = 3; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_past_unsup_bad.pl b/test_regress/t/t_gen_defparam_nfound_bad.pl similarity index 100% rename from test_regress/t/t_past_unsup_bad.pl rename to test_regress/t/t_gen_defparam_nfound_bad.pl diff --git a/test_regress/t/t_gen_defparam_nfound_bad.v b/test_regress/t/t_gen_defparam_nfound_bad.v new file mode 100644 index 000000000..85c1017c6 --- /dev/null +++ b/test_regress/t/t_gen_defparam_nfound_bad.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + a a (); + defparam z.W = 3; // Bad +endmodule + +module a; + parameter W = 0; +endmodule diff --git a/test_regress/t/t_hier_block_cmake/CMakeLists.txt b/test_regress/t/t_hier_block_cmake/CMakeLists.txt index 645be0795..87d396b8b 100644 --- a/test_regress/t/t_hier_block_cmake/CMakeLists.txt +++ b/test_regress/t/t_hier_block_cmake/CMakeLists.txt @@ -10,7 +10,8 @@ # ###################################################################### -cmake_minimum_required (VERSION 3.8) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0074 NEW) project (t_hier_block_cmake) find_package(verilator REQUIRED) diff --git a/test_regress/t/t_hier_block_struct.pl b/test_regress/t/t_hier_block_struct.pl new file mode 100755 index 000000000..0bce0213b --- /dev/null +++ b/test_regress/t/t_hier_block_struct.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ['--hierarchical'] + ); + +execute( + check_finished => 1, + ); + +file_grep($Self->{obj_dir} . "/VTest/Test.sv", /^module\s+(\S+)\s+/, "Test"); + +ok(1); +1; diff --git a/test_regress/t/t_hier_block_struct.v b/test_regress/t/t_hier_block_struct.v new file mode 100644 index 000000000..a3bec94b6 --- /dev/null +++ b/test_regress/t/t_hier_block_struct.v @@ -0,0 +1,98 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Varun Koyyalagunta. +// SPDX-License-Identifier: CC0-1.0 + +typedef struct packed { + logic x; +} nested_named_t; + +typedef struct packed { + struct packed { + logic x; + } nested_anonymous; + nested_named_t nested_named; + logic [1:0] x; +} nibble_t; + +module t( + clk + ); + input clk; + + integer cyc = 0; + logic [63:0] crc; + logic [63:0] sum; + + // Take CRC data and apply to testblock inputs + nibble_t[7:0] in; + assign in = crc[31:0]; + + nibble_t[7:0] out; + + Test test( + .out0 ({out[1], out[0]}), + .out1 ({{out[5], out[4]}, {out[3], out[2]}}), + .out2 (out[6]), + .out3 (out[7]), + .clk (clk), + .in0 (in[0]), + .in1 (in[1]), + .in2 ({in[5], in[4], in[3], in[2]}), + .in3 ({in[7], in[6]})); + + // Aggregate outputs into a single result vector + wire [63:0] result = {32'h0, out}; + + // Test loop + always @ (posedge clk) begin +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d crc=%x result=%x\n", $time, cyc, crc, result); +`endif + cyc <= cyc + 1; + crc <= {crc[62:0], crc[63] ^ crc[2] ^ crc[0]}; + sum <= result ^ {sum[62:0], sum[63] ^ sum[2] ^ sum[0]}; + if (cyc == 0) begin + // Setup + crc <= 64'h5aef0c8d_d70a4497; + sum <= '0; + end + else if (cyc < 10) begin + sum <= '0; + end + else if (cyc < 90) begin + end + else if (cyc == 99) begin + $write("[%0t] cyc==%0d crc=%x sum=%x\n", $time, cyc, crc, sum); + if (crc !== 64'hc77bb9b3784ea091) $stop; + // What checksum will we end up with (above print should match) +`define EXPECTED_SUM 64'h4afe43fb79d7b71e + if (sum !== `EXPECTED_SUM) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + +module Test( + // Outputs + output nibble_t [1:0] out0, + output nibble_t [1:0] out1[2], + output nibble_t out2, + output nibble_t out3, + // Inputs + input clk, + input nibble_t in0, + input nibble_t in1, + input nibble_t [3:0] in2, + input nibble_t in3[2] + ); /*verilator hier_block*/ + + + always @(posedge clk) begin + {out3, out2, out1[0], out1[1], out0} <= {in3[0], in3[1], in2, in1, in0}; + end + +endmodule diff --git a/test_regress/t/t_hier_task.v b/test_regress/t/t_hier_task.v index dfd3f7948..42fe3eff2 100644 --- a/test_regress/t/t_hier_task.v +++ b/test_regress/t/t_hier_task.v @@ -39,7 +39,7 @@ endmodule : mod_inner module mod_a_mon; bit y; - function void accessor; + function automatic void accessor; begin : accessor_block bit read_x = mod_a.u_inner.x; y = read_x; diff --git a/test_regress/t/t_implements.pl b/test_regress/t/t_implements.pl new file mode 100755 index 000000000..da2e37bda --- /dev/null +++ b/test_regress/t/t_implements.pl @@ -0,0 +1,17 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements.v b/test_regress/t/t_implements.v new file mode 100644 index 000000000..caad29c82 --- /dev/null +++ b/test_regress/t/t_implements.v @@ -0,0 +1,70 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +interface class Icempty; +endclass : Icempty + +interface class Icls1; + localparam LP1 = 1; + pure virtual function int icf1; + pure virtual function int icfboth; + pure virtual function int icfpartial; +endclass + +interface class Iext1 extends Icls1; + pure virtual function int icf101; +endclass + +interface class Icls2; + pure virtual function int icf2(int in); + pure virtual function int icfboth; +endclass + +virtual class Base implements Iext1, Icls2; + virtual function int icf1; + return 1; + endfunction + virtual function int icf101; + return 101; + endfunction + virtual function int icf2(int in); + return in + 2; + endfunction + virtual function int icfboth; + return 3; + endfunction + pure virtual function int icfpartial; +endclass + +class Cls extends Base; + virtual function int icfpartial; + return 62; + endfunction +endclass + +module t(/*AUTOARG*/); + + Cls c; + Iext1 i1; + + initial begin + if (Icls1::LP1 != 1) $stop; + + c = new; + if (c.icf1() != 1) $stop; + if (c.icf101() != 101) $stop; + if (c.icf2(1000) != 1002) $stop; + if (c.icfpartial() != 62) $stop; + + i1 = c; + if (i1.icf1() != 1) $stop; + if (i1.icf101() != 101) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_implements_collision.pl b/test_regress/t/t_implements_collision.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_implements_collision.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_collision.v b/test_regress/t/t_implements_collision.v new file mode 100644 index 000000000..d0032ade0 --- /dev/null +++ b/test_regress/t/t_implements_collision.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +interface class Icls1; + pure virtual function int icfboth; +endclass + +interface class Icls2; + pure virtual function int icfboth; +endclass + +interface class IclsBoth extends Icls1, Icls2; + pure virtual function int icfboth; +endclass + +class Cls implements IclsBoth; + virtual function int icfboth; + return 3; + endfunction +endclass + +module t(/*AUTOARG*/); + + Cls c; + + initial begin + c = new; + if (c.icfboth() != 3) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_implements_collision_bad.out b/test_regress/t/t_implements_collision_bad.out new file mode 100644 index 000000000..80fecac8e --- /dev/null +++ b/test_regress/t/t_implements_collision_bad.out @@ -0,0 +1,13 @@ +%Error: t/t_implements_collision_bad.v:15:11: Class 'IclsBoth' implements 'Icls2' but missing inheritance conflict resolution for 'icfboth' (IEEE 1800-2017 8.26.6.2) + 15 | interface class IclsBoth extends Icls1, Icls2; + | ^~~~~ + t/t_implements_collision_bad.v:12:30: ... Location of interface class's function + 12 | pure virtual function int icfboth; + | ^~~~~~~ +%Error: t/t_implements_collision_bad.v:19:1: Class 'Cls' implements 'IclsBoth' but is missing implementation for 'icfboth' (IEEE 1800-2017 8.26) + 19 | class Cls implements IclsBoth; + | ^~~~~ + t/t_implements_collision_bad.v:8:30: ... Location of interface class's function + 8 | pure virtual function int icfboth; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_implements_collision_bad.pl b/test_regress/t/t_implements_collision_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_implements_collision_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_collision_bad.v b/test_regress/t/t_implements_collision_bad.v new file mode 100644 index 000000000..d457be661 --- /dev/null +++ b/test_regress/t/t_implements_collision_bad.v @@ -0,0 +1,24 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +interface class Icls1; + pure virtual function int icfboth; +endclass + +interface class Icls2; + pure virtual function int icfboth; +endclass + +interface class IclsBoth extends Icls1, Icls2; + // Bad collision on icfboth +endclass + +class Cls implements IclsBoth; +endclass + +module t (/*AUTOARG*/); + Cls c; +endmodule diff --git a/test_regress/t/t_implements_contents_bad.out b/test_regress/t/t_implements_contents_bad.out new file mode 100644 index 000000000..642eec558 --- /dev/null +++ b/test_regress/t/t_implements_contents_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_implements_contents_bad.v:8:8: Interface class cannot contain non-parameter members (IEEE 1800-2017 8.26): 'badi' + 8 | int badi; + | ^~~~ +%Error: t/t_implements_contents_bad.v:9:9: Interface class functions must be pure virtual (IEEE 1800-2017 8.26): 'badtask' + 9 | task badtask; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_implements_contents_bad.pl b/test_regress/t/t_implements_contents_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_implements_contents_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_contents_bad.v b/test_regress/t/t_implements_contents_bad.v new file mode 100644 index 000000000..4106c7ed4 --- /dev/null +++ b/test_regress/t/t_implements_contents_bad.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +interface class Icls; + int badi; + task badtask; + endtask +endclass + +module t (/*AUTOARG*/); +endmodule diff --git a/test_regress/t/t_implements_missing_bad.out b/test_regress/t/t_implements_missing_bad.out new file mode 100644 index 000000000..67c410cc6 --- /dev/null +++ b/test_regress/t/t_implements_missing_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_implements_missing_bad.v:12:1: Class 'Cls' implements 'Icls1' but is missing implementation for 'icf2' (IEEE 1800-2017 8.26) + 12 | class Cls implements Icls1; + | ^~~~~ + t/t_implements_missing_bad.v:9:30: ... Location of interface class's function + 9 | pure virtual function int icf2; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_implements_missing_bad.pl b/test_regress/t/t_implements_missing_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_implements_missing_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_missing_bad.v b/test_regress/t/t_implements_missing_bad.v new file mode 100644 index 000000000..f84eb6ae3 --- /dev/null +++ b/test_regress/t/t_implements_missing_bad.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +interface class Icls1; + pure virtual function int icf1; + pure virtual function int icf2; +endclass + +class Cls implements Icls1; + virtual function int icf1; + return 1; + endfunction + // Bad missing icf2 +endclass + +module t (/*AUTOARG*/); + Cls c; +endmodule diff --git a/test_regress/t/t_implements_nested_bad.out b/test_regress/t/t_implements_nested_bad.out new file mode 100644 index 000000000..1121c001f --- /dev/null +++ b/test_regress/t/t_implements_nested_bad.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_implements_nested_bad.v:8:14: Unsupported: class within class + 8 | interface class bad_cannot_nest; + | ^~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_implements_nested_bad.pl b/test_regress/t/t_implements_nested_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_implements_nested_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_nested_bad.v b/test_regress/t/t_implements_nested_bad.v new file mode 100644 index 000000000..119033fa3 --- /dev/null +++ b/test_regress/t/t_implements_nested_bad.v @@ -0,0 +1,14 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + interface class bad_cannot_nest; + endclass +endclass + +module t (/*AUTOARG*/); + Cls c; +endmodule diff --git a/test_regress/t/t_implements_new_bad.out b/test_regress/t/t_implements_new_bad.out new file mode 100644 index 000000000..e86450d3a --- /dev/null +++ b/test_regress/t/t_implements_new_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_implements_new_bad.v:13:11: Illegal to call 'new' using an abstract virtual class (IEEE 1800-2017 8.21) + : ... In instance t + 13 | c = new; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_implements_new_bad.pl b/test_regress/t/t_implements_new_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_implements_new_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_union_unpacked_bad.v b/test_regress/t/t_implements_new_bad.v similarity index 59% rename from test_regress/t/t_union_unpacked_bad.v rename to test_regress/t/t_implements_new_bad.v index d93b5ec5b..950039100 100644 --- a/test_regress/t/t_union_unpacked_bad.v +++ b/test_regress/t/t_implements_new_bad.v @@ -1,20 +1,16 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2009 by Wilson Snyder. +// any use, without warranty, 2023 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -module x; - - typedef union { - int a; - } union_t; - - union_t b; +interface class Icls; +endclass +module t (/*AUTOARG*/); + Icls c; initial begin - b = 1; - if (b != 1) $stop; + c = new; // Bad $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_implements_noinherit_bad.out b/test_regress/t/t_implements_noinherit_bad.out new file mode 100644 index 000000000..d93b92911 --- /dev/null +++ b/test_regress/t/t_implements_noinherit_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_implements_noinherit_bad.v:14:16: Can't find definition of variable: 'IP' + 14 | $display(IP); + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_implements_noinherit_bad.pl b/test_regress/t/t_implements_noinherit_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_implements_noinherit_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_noinherit_bad.v b/test_regress/t/t_implements_noinherit_bad.v new file mode 100644 index 000000000..8726e86fc --- /dev/null +++ b/test_regress/t/t_implements_noinherit_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +interface class Icls; + localparam IP = 1; + typedef int i_t; +endclass + +class Cls implements Icls; + function void f; + $display(IP); // Bad + endfunction +endclass + +module t (/*AUTOARG*/); + Cls c; +endmodule diff --git a/test_regress/t/t_implements_noninterface_bad.out b/test_regress/t/t_implements_noninterface_bad.out new file mode 100644 index 000000000..56fc33832 --- /dev/null +++ b/test_regress/t/t_implements_noninterface_bad.out @@ -0,0 +1,9 @@ +%Error: t/t_implements_noninterface_bad.v:10:26: Attempting to implement from non-interface class 'NotIcls' +... Suggest use 'extends' + 10 | class ClsBad1 implements NotIcls; + | ^~~~~~~ +%Error: t/t_implements_noninterface_bad.v:16:23: Attempting to extend from interface class 'Icls' +... Suggest use 'implements' + 16 | class ClsBad2 extends Icls; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_implements_noninterface_bad.pl b/test_regress/t/t_implements_noninterface_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_implements_noninterface_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_noninterface_bad.v b/test_regress/t/t_implements_noninterface_bad.v new file mode 100644 index 000000000..95ff76301 --- /dev/null +++ b/test_regress/t/t_implements_noninterface_bad.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class NotIcls; +endclass + +class ClsBad1 implements NotIcls; +endclass + +interface class Icls; +endclass + +class ClsBad2 extends Icls; +endclass + +module t (/*AUTOARG*/); + Cls c; +endmodule diff --git a/test_regress/t/t_implements_notfound_bad.out b/test_regress/t/t_implements_notfound_bad.out new file mode 100644 index 000000000..19bc6b6d0 --- /dev/null +++ b/test_regress/t/t_implements_notfound_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_implements_notfound_bad.v:7:23: Class for 'implements' not found: 'Inotfound' + 7 | class ClsI implements Inotfound; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_implements_notfound_bad.pl b/test_regress/t/t_implements_notfound_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_implements_notfound_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_notfound_bad.v b/test_regress/t/t_implements_notfound_bad.v new file mode 100644 index 000000000..66a3bef0f --- /dev/null +++ b/test_regress/t/t_implements_notfound_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class ClsI implements Inotfound; +endclass + +module t (/*AUTOARG*/); + ClsI ci; +endmodule diff --git a/test_regress/t/t_implements_typed.pl b/test_regress/t/t_implements_typed.pl new file mode 100755 index 000000000..da2e37bda --- /dev/null +++ b/test_regress/t/t_implements_typed.pl @@ -0,0 +1,17 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_implements_typed.v b/test_regress/t/t_implements_typed.v new file mode 100644 index 000000000..128e3c7cd --- /dev/null +++ b/test_regress/t/t_implements_typed.v @@ -0,0 +1,41 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +interface class Icls; + typedef int int_t; + pure virtual function int ifunc(int_t val); +endclass + +interface class IclsExt extends Icls; + // Typedefs seen by extended, but not implements (need ::) + pure virtual function int ifuncExt(int_t v1, int_t v2); +endclass + +class IclsImp implements Icls; + function int ifunc(Icls::int_t val); + return val + 1; + endfunction +endclass + +// Bad, already have error for +// class IclsImp2 implements Icls; +// function int ifunc(int_t val); // Bad int_t not typedefed +// endfunction +// endclass + +module t(/*AUTOARG*/); + + IclsImp i1; + + initial begin + i1 = new; + if (i1.ifunc(2) != 3) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_incr_void.v b/test_regress/t/t_incr_void.v index eebf410aa..75284fcd7 100644 --- a/test_regress/t/t_incr_void.v +++ b/test_regress/t/t_incr_void.v @@ -1,3 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Drew Ranck. +// SPDX-License-Identifier: CC0-1.0 + module t (/*AUTOARG*/ // Inputs diff --git a/test_regress/t/t_inst_2star_bad.out b/test_regress/t/t_inst_2star_bad.out index fc7cc9140..b4d6f2922 100644 --- a/test_regress/t/t_inst_2star_bad.out +++ b/test_regress/t/t_inst_2star_bad.out @@ -1,7 +1,10 @@ -%Error: t/t_inst_2star_bad.v:11:17: Duplicate .* in an instance (IEEE 1800-2017 23.3.2) - 11 | sub sub (.*, .*); +%Error: t/t_inst_2star_bad.v:12:17: Duplicate .* in an instance (IEEE 1800-2017 23.3.2) + 12 | sub sub (.*, .*); | ^~ -%Error: t/t_inst_2star_bad.v:13:13: Connect by position is illegal in .* connected instances (IEEE 1800-2017 23.3.2) - 13 | sub sub (foo, .*); +%Error: t/t_inst_2star_bad.v:14:13: Mixing positional and .*/named instantiation connection (IEEE 1800-2017 23.3.2) + 14 | sub sub (foo, .*); + | ^~~ +%Error: t/t_inst_2star_bad.v:16:13: Mixing positional and .*/named instantiation connection (IEEE 1800-2017 23.3.2) + 16 | sub sub (foo, .bar); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_2star_bad.v b/test_regress/t/t_inst_2star_bad.v index 5c91aaac5..74e527c9d 100644 --- a/test_regress/t/t_inst_2star_bad.v +++ b/test_regress/t/t_inst_2star_bad.v @@ -7,12 +7,15 @@ module t (/*AUTOARG*/); wire foo; + wire bar; sub sub (.*, .*); sub sub (foo, .*); + sub sub (foo, .bar); + endmodule -module sub (input foo); +module sub (input foo, input bar); endmodule diff --git a/test_regress/t/t_inst_missing.v b/test_regress/t/t_inst_missing.v index 69ecc51fe..081be8f5d 100644 --- a/test_regress/t/t_inst_missing.v +++ b/test_regress/t/t_inst_missing.v @@ -6,9 +6,13 @@ module t (/*AUTOARG*/); wire ok = 1'b0; + // verilator lint_off UNDRIVEN + wire nc; + // verilator lint_on UNDRIVEN + // verilator lint_off PINNOCONNECT // verilator lint_off PINCONNECTEMPTY - sub sub (.ok(ok), , .nc()); + sub sub (ok, , nc); // verilator lint_on PINCONNECTEMPTY // verilator lint_on PINNOCONNECT endmodule diff --git a/test_regress/t/t_inst_missing_bad.out b/test_regress/t/t_inst_missing_bad.out index 8f676d048..c716cf0a5 100644 --- a/test_regress/t/t_inst_missing_bad.out +++ b/test_regress/t/t_inst_missing_bad.out @@ -1,12 +1,9 @@ -%Warning-PINNOCONNECT: t/t_inst_missing_bad.v:9:22: Cell pin is not connected: '__pinNumber2' - 9 | sub sub (.ok(ok), , .nc()); - | ^ +%Warning-PINNOCONNECT: t/t_inst_missing_bad.v:13:17: Cell pin is not connected: '__pinNumber2' + 13 | sub sub (ok, , nc); + | ^ ... For warning description see https://verilator.org/warn/PINNOCONNECT?v=latest ... Use "/* verilator lint_off PINNOCONNECT */" and lint_on around source to disable this message. -%Warning-PINCONNECTEMPTY: t/t_inst_missing_bad.v:9:25: Cell pin connected by name with empty reference: 'nc' - 9 | sub sub (.ok(ok), , .nc()); - | ^~ -%Warning-PINMISSING: t/t_inst_missing_bad.v:9:8: Cell has missing pin: 'missing' - 9 | sub sub (.ok(ok), , .nc()); +%Warning-PINMISSING: t/t_inst_missing_bad.v:13:8: Cell has missing pin: 'missing' + 13 | sub sub (ok, , nc); | ^~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_missing_bad.v b/test_regress/t/t_inst_missing_bad.v index 73f782433..2d0c703fe 100644 --- a/test_regress/t/t_inst_missing_bad.v +++ b/test_regress/t/t_inst_missing_bad.v @@ -6,7 +6,11 @@ module t (/*AUTOARG*/); wire ok = 1'b0; - sub sub (.ok(ok), , .nc()); + // verilator lint_off UNDRIVEN + wire nc; + // verilator lint_on UNDRIVEN + + sub sub (ok, , nc); endmodule module sub (input ok, input none, input nc, input missing); diff --git a/test_regress/t/t_inst_overwide_bad.out b/test_regress/t/t_inst_overwide_bad.out index 5a2a10068..6bf85b1c5 100644 --- a/test_regress/t/t_inst_overwide_bad.out +++ b/test_regress/t/t_inst_overwide_bad.out @@ -1,19 +1,19 @@ -%Warning-WIDTH: t/t_inst_overwide.v:23:14: Output port connection 'outy_w92' expects 92 bits on the pin connection, but pin connection's VARREF 'outc_w30' generates 30 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_inst_overwide.v:23:14: Output port connection 'outy_w92' expects 92 bits on the pin connection, but pin connection's VARREF 'outc_w30' generates 30 bits. + : ... In instance t 23 | .outy_w92 (outc_w30), | ^~~~~~~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. -%Warning-WIDTH: t/t_inst_overwide.v:24:14: Output port connection 'outz_w22' expects 22 bits on the pin connection, but pin connection's VARREF 'outd_w73' generates 73 bits. - : ... In instance t + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. +%Warning-WIDTHTRUNC: t/t_inst_overwide.v:24:14: Output port connection 'outz_w22' expects 22 bits on the pin connection, but pin connection's VARREF 'outd_w73' generates 73 bits. + : ... In instance t 24 | .outz_w22 (outd_w73), | ^~~~~~~~ -%Warning-WIDTH: t/t_inst_overwide.v:27:14: Input port connection 'inw_w31' expects 31 bits on the pin connection, but pin connection's VARREF 'ina_w1' generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_inst_overwide.v:27:14: Input port connection 'inw_w31' expects 31 bits on the pin connection, but pin connection's VARREF 'ina_w1' generates 1 bits. + : ... In instance t 27 | .inw_w31 (ina_w1), | ^~~~~~~ -%Warning-WIDTH: t/t_inst_overwide.v:28:14: Input port connection 'inx_w11' expects 11 bits on the pin connection, but pin connection's VARREF 'inb_w61' generates 61 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_inst_overwide.v:28:14: Input port connection 'inx_w11' expects 11 bits on the pin connection, but pin connection's VARREF 'inb_w61' generates 61 bits. + : ... In instance t 28 | .inx_w11 (inb_w61) | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_inst_pin_realnreal.out b/test_regress/t/t_inst_pin_realnreal.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_inst_tree_inl0_pub0.pl b/test_regress/t/t_inst_tree_inl0_pub0.pl index 8f0584454..765664407 100755 --- a/test_regress/t/t_inst_tree_inl0_pub0.pl +++ b/test_regress/t/t_inst_tree_inl0_pub0.pl @@ -18,12 +18,12 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_inst_tree_inl1_pub0.pl b/test_regress/t/t_inst_tree_inl1_pub0.pl index b8f738b3e..2aac81bfc 100755 --- a/test_regress/t/t_inst_tree_inl1_pub0.pl +++ b/test_regress/t/t_inst_tree_inl1_pub0.pl @@ -18,9 +18,9 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_inst_tree_inl1_pub1.pl b/test_regress/t/t_inst_tree_inl1_pub1.pl index 4240d8339..33596f45b 100755 --- a/test_regress/t/t_inst_tree_inl1_pub1.pl +++ b/test_regress/t/t_inst_tree_inl1_pub1.pl @@ -19,9 +19,9 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_interconnect.out b/test_regress/t/t_interconnect.out new file mode 100644 index 000000000..7cc18791b --- /dev/null +++ b/test_regress/t/t_interconnect.out @@ -0,0 +1,14 @@ +%Error-UNSUPPORTED: t/t_interconnect.v:12:4: Unsupported: interconnect + 12 | interconnect a; + | ^~~~~~~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_interconnect.v:13:4: Unsupported: interconnect + 13 | interconnect b; + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_interconnect.v:22:11: Unsupported: interconnect + 22 | output interconnect a, + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_interconnect.v:23:11: Unsupported: interconnect + 23 | output interconnect b); + | ^~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_interconnect.pl b/test_regress/t/t_interconnect.pl new file mode 100755 index 000000000..2a516857f --- /dev/null +++ b/test_regress/t/t_interconnect.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--timing"], + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_interconnect.v b/test_regress/t/t_interconnect.v new file mode 100644 index 000000000..56560484a --- /dev/null +++ b/test_regress/t/t_interconnect.v @@ -0,0 +1,49 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// Note: Other simulator's support for interconnect seems rare, the below might +// not be correct code. + +module t(/*AUTOARG*/); + + interconnect a; + interconnect b; + + moda suba (.a, .b); + modb #(.TA_t(real)) subb (.a(a), .b(b)); + +endmodule + +module moda + ( + output interconnect a, + output interconnect b); + modaa subaa (.a, .b); +endmodule + +module modaa + ( + output real a, + output int b); + initial begin + a = 1.234; + b = 1234; + end +endmodule + +module modb + #(parameter type TA_t = int) + ( + input TA_t a, + input int b); + initial begin + #10; + if (a != 1.234) $stop; + if (b != 1234) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_interconnect_bad.out b/test_regress/t/t_interconnect_bad.out new file mode 100644 index 000000000..061e7f1e2 --- /dev/null +++ b/test_regress/t/t_interconnect_bad.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_interconnect_bad.v:9:4: Unsupported: interconnect + 9 | interconnect a; + | ^~~~~~~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_interconnect_bad.pl b/test_regress/t/t_interconnect_bad.pl new file mode 100755 index 000000000..1362bf74f --- /dev/null +++ b/test_regress/t/t_interconnect_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_interconnect_bad.v b/test_regress/t/t_interconnect_bad.v new file mode 100644 index 000000000..92fb8f940 --- /dev/null +++ b/test_regress/t/t_interconnect_bad.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + interconnect a; + + assign a = 1; // Bad IEEE 6.6.8 - shall not be used in continuous assignment + + initial begin + a = 2; // Bad IEEE 6.6.8 - shall not be used in procedural assignment + end + +endmodule diff --git a/test_regress/t/t_interface_array_nocolon_bad.out b/test_regress/t/t_interface_array_nocolon_bad.out index f741b3b24..b189edec7 100644 --- a/test_regress/t/t_interface_array_nocolon_bad.out +++ b/test_regress/t/t_interface_array_nocolon_bad.out @@ -1,18 +1,18 @@ -%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:26:26: Little endian instance range connecting to vector: left < right of instance range: [0:2] +%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:26:26: Big endian instance range connecting to vector: left < right of instance range: [0:2] : ... In instance t 26 | foo_intf foos [N] (.x(X)); | ^ ... For warning description see https://verilator.org/warn/LITENDIAN?v=latest ... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message. -%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:27:28: Little endian instance range connecting to vector: left < right of instance range: [1:3] +%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:27:28: Big endian instance range connecting to vector: left < right of instance range: [1:3] : ... In instance t 27 | foo_intf fool [1:3] (.x(X)); | ^ -%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:30:26: Little endian instance range connecting to vector: left < right of instance range: [0:2] +%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:30:26: Big endian instance range connecting to vector: left < right of instance range: [0:2] : ... In instance t 30 | foo_subm subs [N] (.x(X)); | ^ -%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:31:28: Little endian instance range connecting to vector: left < right of instance range: [1:3] +%Warning-LITENDIAN: t/t_interface_array_nocolon_bad.v:31:28: Big endian instance range connecting to vector: left < right of instance range: [1:3] : ... In instance t 31 | foo_subm subl [1:3] (.x(X)); | ^ diff --git a/test_regress/t/t_interface_modport_import_export_list.pl b/test_regress/t/t_interface_modport_import_export_list.pl index 5412e6e24..c74d44be5 100755 --- a/test_regress/t/t_interface_modport_import_export_list.pl +++ b/test_regress/t/t_interface_modport_import_export_list.pl @@ -10,9 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( - fails=>0, -); +compile(); ok(1); 1; diff --git a/test_regress/t/t_interface_modport_import_export_list.v b/test_regress/t/t_interface_modport_import_export_list.v index ddefa9700..a44673327 100644 --- a/test_regress/t/t_interface_modport_import_export_list.v +++ b/test_regress/t/t_interface_modport_import_export_list.v @@ -7,48 +7,50 @@ // SPDX-License-Identifier: CC0-1.0 interface intf; - logic l; - function void f1(); - endfunction - function void f2(); - endfunction - function void f3(); - endfunction - function void f4(); - endfunction + logic l; + function void f1(); + endfunction + function void f2(); + endfunction + function void f3(); + endfunction + function void f4(); + endfunction - modport mpi ( - import f1, f2, - input l, - import f3, f4 - ); - modport mpo ( - output l, - import f1, f2, f3, f4 - ); + modport mpi + ( + import f1, f2, + input l, + import f3, f4 + ); + modport mpo + ( + output l, + import f1, f2, f3, f4 + ); endinterface module mo (intf.mpo intf0); - function void ef1(); - intf0.f1(); - intf0.f2(); - endfunction - function void ef2(); - intf0.f3(); - intf0.f4(); - endfunction + function void ef1(); + intf0.f1(); + intf0.f2(); + endfunction + function void ef2(); + intf0.f3(); + intf0.f4(); + endfunction -initial begin - ef1(); - ef2(); -end + initial begin + ef1(); + ef2(); + end endmodule module mi (intf.mpi intf0); endmodule module t; - intf intf0(); - mi mi(.*); - mo mo(.*); + intf intf0(); + mi mi(.*); + mo mo(.*); endmodule diff --git a/test_regress/t/t_interface_modportlist.v b/test_regress/t/t_interface_modportlist.v index c72fa490f..7391bfcb0 100644 --- a/test_regress/t/t_interface_modportlist.v +++ b/test_regress/t/t_interface_modportlist.v @@ -8,7 +8,7 @@ module t(input clk); my_interface iface(); - my_module m(.clk(clk), iface); + my_module m(.clk(clk), .iface); endmodule module my_module(input clk, my_interface.my_port iface); diff --git a/test_regress/t/t_lint_always_comb_multidriven.out b/test_regress/t/t_lint_always_comb_multidriven.out new file mode 100644 index 000000000..e57a462a5 --- /dev/null +++ b/test_regress/t/t_lint_always_comb_multidriven.out @@ -0,0 +1,87 @@ +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:26:16: Variable written to in always_comb also written by other process (IEEE 1800-2017 9.2.2.2): 'out1' + : ... In instance t + t/t_lint_always_comb_multidriven.v:26:16: + 26 | always_comb out1 = d; + | ^~~~ + t/t_lint_always_comb_multidriven.v:25:11: ... Location of other write + 25 | assign out1 = 1'b0; + | ^~~~ + ... For warning description see https://verilator.org/warn/MULTIDRIVEN?v=latest + ... Use "/* verilator lint_off MULTIDRIVEN */" and lint_on around source to disable this message. +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:29:16: Variable written to in always_comb also written by other process (IEEE 1800-2017 9.2.2.2): 'out2' + : ... In instance t + t/t_lint_always_comb_multidriven.v:29:16: + 29 | always_comb out2 = 1'b0; + | ^~~~ + t/t_lint_always_comb_multidriven.v:28:11: ... Location of other write + 28 | assign out2 = d; + | ^~~~ +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:32:11: Variable also written to in always_comb (IEEE 1800-2017 9.2.2.2): 'out3' + : ... In instance t + t/t_lint_always_comb_multidriven.v:32:11: + 32 | assign out3 = 1'b0; + | ^~~~ + t/t_lint_always_comb_multidriven.v:31:16: ... Location of always_comb write + 31 | always_comb out3 = d; + | ^~~~ +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:35:11: Variable also written to in always_comb (IEEE 1800-2017 9.2.2.2): 'out4' + : ... In instance t + t/t_lint_always_comb_multidriven.v:35:11: + 35 | assign out4 = d; + | ^~~~ + t/t_lint_always_comb_multidriven.v:34:16: ... Location of always_comb write + 34 | always_comb out4 = 1'b0; + | ^~~~ +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:38:16: Variable written to in always_comb also written by other process (IEEE 1800-2017 9.2.2.2): 'out5' + : ... In instance t + t/t_lint_always_comb_multidriven.v:38:16: + 38 | always_comb out5 = d; + | ^~~~ + t/t_lint_always_comb_multidriven.v:37:16: ... Location of other write + 37 | always_comb out5 = 1'b0; + | ^~~~ +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:41:16: Variable written to in always_comb also written by other process (IEEE 1800-2017 9.2.2.2): 'out6' + : ... In instance t + t/t_lint_always_comb_multidriven.v:41:16: + 41 | always_comb out6 = 1'b0; + | ^~~~ + t/t_lint_always_comb_multidriven.v:40:16: ... Location of other write + 40 | always_comb out6 = d; + | ^~~~ +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:17:15: Bits [0:0] of signal 'out2' have multiple combinational drivers + : ... In instance t + t/t_lint_always_comb_multidriven.v:28:16: ... Location of first driver + 28 | assign out2 = d; + | ^ + t/t_lint_always_comb_multidriven.v:29:21: ... Location of other driver + 29 | always_comb out2 = 1'b0; + | ^ + t/t_lint_always_comb_multidriven.v:17:15: ... Only the first driver will be respected +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:19:15: Bits [0:0] of signal 'out4' have multiple combinational drivers + : ... In instance t + t/t_lint_always_comb_multidriven.v:34:21: ... Location of first driver + 34 | always_comb out4 = 1'b0; + | ^ + t/t_lint_always_comb_multidriven.v:35:16: ... Location of other driver + 35 | assign out4 = d; + | ^ + t/t_lint_always_comb_multidriven.v:19:15: ... Only the first driver will be respected +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:20:15: Bits [0:0] of signal 'out5' have multiple combinational drivers + : ... In instance t + t/t_lint_always_comb_multidriven.v:37:21: ... Location of first driver + 37 | always_comb out5 = 1'b0; + | ^ + t/t_lint_always_comb_multidriven.v:38:21: ... Location of other driver + 38 | always_comb out5 = d; + | ^ + t/t_lint_always_comb_multidriven.v:20:15: ... Only the first driver will be respected +%Warning-MULTIDRIVEN: t/t_lint_always_comb_multidriven.v:21:15: Bits [0:0] of signal 'out6' have multiple combinational drivers + : ... In instance t + t/t_lint_always_comb_multidriven.v:40:21: ... Location of first driver + 40 | always_comb out6 = d; + | ^ + t/t_lint_always_comb_multidriven.v:41:21: ... Location of other driver + 41 | always_comb out6 = 1'b0; + | ^ + t/t_lint_always_comb_multidriven.v:21:15: ... Only the first driver will be respected +%Error: Exiting due to diff --git a/test_regress/t/t_lint_always_comb_multidriven.pl b/test_regress/t/t_lint_always_comb_multidriven.pl new file mode 100755 index 000000000..4786ecc50 --- /dev/null +++ b/test_regress/t/t_lint_always_comb_multidriven.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + verilator_flags2 => ['--lint-only'], + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_always_comb_multidriven.v b/test_regress/t/t_lint_always_comb_multidriven.v new file mode 100644 index 000000000..a243bbd59 --- /dev/null +++ b/test_regress/t/t_lint_always_comb_multidriven.v @@ -0,0 +1,76 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2012 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Outputs + out1, out2, out3, out4, out5, out6, out7, out8, + // Inputs + clk, d + ); + + input clk; + input d; + output reg out1; + output reg out2; + output reg out3; + output reg out4; + output reg out5; + output reg out6; + output reg out7; + output reg out8; + + assign out1 = 1'b0; + always_comb out1 = d; // <--- Warning + + assign out2 = d; + always_comb out2 = 1'b0; // <--- Warning + + always_comb out3 = d; + assign out3 = 1'b0; // <--- Warning + + always_comb out4 = 1'b0; + assign out4 = d; // <--- Warning + + always_comb out5 = 1'b0; + always_comb out5 = d; // <--- Warning + + always_comb out6 = d; + always_comb out6 = 1'b0; // <--- Warning + + always_comb begin + out7 = 1'b0; + out7 = d; + end + + always_comb begin + out8 = d; + out8 = 1'b0; + end + + reg [1:0] arr_packed; + reg arr_unpacked [0:1]; + reg [1:0] gen_arr_packed; + reg gen_arr_unpacked [0:1]; + genvar g; + + always_comb begin + arr_packed[0] = d; + arr_packed[1] = d; + end + + always_comb begin + arr_unpacked[0] = d; + arr_unpacked[1] = d; + end + + generate + for (g=0; g<2; ++g) begin + always_comb gen_arr_packed[g] = d; + always_comb gen_arr_unpacked[g] = d; + end + endgenerate + +endmodule diff --git a/test_regress/t/t_lint_always_comb_multidriven_compile_public_flat.pl b/test_regress/t/t_lint_always_comb_multidriven_compile_public_flat.pl new file mode 100755 index 000000000..9cf2c191e --- /dev/null +++ b/test_regress/t/t_lint_always_comb_multidriven_compile_public_flat.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_lint_always_comb_multidriven.v"); + +lint( + verilator_flags2 => ['--public-flat-rw --lint-only'], + fails => 1, + expect_filename => "t/t_lint_always_comb_multidriven.out", + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_edge_real_bad.out b/test_regress/t/t_lint_edge_real_bad.out index c3fbd266c..6932b75ea 100644 --- a/test_regress/t/t_lint_edge_real_bad.out +++ b/test_regress/t/t_lint_edge_real_bad.out @@ -1,5 +1,9 @@ -%Error: t/t_lint_edge_real_bad.v:16:22: Edge event control not legal on real type (IEEE 1800-2017 6.12.1) +%Error: t/t_lint_edge_real_bad.v:19:22: Edge event control not legal on real type (IEEE 1800-2017 6.12.1) : ... In instance t - 16 | always @ (posedge rbad) $stop; + 19 | always @ (posedge rbad) $stop; + | ^~~~ +%Error: t/t_lint_edge_real_bad.v:20:22: Edge event control not legal on non-integral type (IEEE 1800-2017 9.4.2) + : ... In instance t + 20 | always @ (posedge ebad) $stop; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_edge_real_bad.v b/test_regress/t/t_lint_edge_real_bad.v index 58dfad8ad..4db3ae293 100644 --- a/test_regress/t/t_lint_edge_real_bad.v +++ b/test_regress/t/t_lint_edge_real_bad.v @@ -10,9 +10,13 @@ module t (/*AUTOARG*/ ); input real rbad; input real rok; + event ebad; + struct packed { int a; } sok; always @ (rok) $stop; + always @ (sok) $stop; always @ (posedge rbad) $stop; + always @ (posedge ebad) $stop; endmodule diff --git a/test_regress/t/t_lint_eofline_vlt.vlt b/test_regress/t/t_lint_eofline_vlt.vlt old mode 100755 new mode 100644 diff --git a/test_regress/t/t_lint_literal_bad.out b/test_regress/t/t_lint_literal_bad.out index 5cab1d60b..81f3808be 100644 --- a/test_regress/t/t_lint_literal_bad.out +++ b/test_regress/t/t_lint_literal_bad.out @@ -1,6 +1,6 @@ -%Warning-WIDTH: t/t_lint_literal_bad.v:10:33: Value too large for 8 bit number: 256 +%Warning-WIDTHTRUNC: t/t_lint_literal_bad.v:10:33: Value too large for 8 bit number: 256 10 | localparam the_localparam = 8'd256; | ^~~~~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_lint_repeat_bad.out b/test_regress/t/t_lint_repeat_bad.out index 35067222b..de1fa2a99 100644 --- a/test_regress/t/t_lint_repeat_bad.out +++ b/test_regress/t/t_lint_repeat_bad.out @@ -1,7 +1,7 @@ -%Warning-WIDTH: t/t_lint_repeat_bad.v:18:17: Operator ASSIGNW expects 1 bits on the Assign RHS, but Assign RHS's VARREF 'a' generates 2 bits. - : ... In instance t.sub3 +%Warning-WIDTHTRUNC: t/t_lint_repeat_bad.v:18:17: Operator ASSIGNW expects 1 bits on the Assign RHS, but Assign RHS's VARREF 'a' generates 2 bits. + : ... In instance t.sub3 18 | wire [0:0] b = a; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_lint_restore_bad.out b/test_regress/t/t_lint_restore_bad.out index a38fcff3e..3f219f8e6 100644 --- a/test_regress/t/t_lint_restore_bad.out +++ b/test_regress/t/t_lint_restore_bad.out @@ -1,7 +1,7 @@ -%Warning-WIDTH: t/t_lint_restore_bad.v:19:17: Operator ASSIGN expects 5 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_lint_restore_bad.v:19:17: Operator ASSIGN expects 5 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. + : ... In instance t 19 | initial five = 64'h1; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_lint_width_bad.out b/test_regress/t/t_lint_width_bad.out index d1faa06e6..dc841f05d 100644 --- a/test_regress/t/t_lint_width_bad.out +++ b/test_regress/t/t_lint_width_bad.out @@ -1,47 +1,47 @@ -%Warning-WIDTH: t/t_lint_width_bad.v:17:25: Operator VAR 'XS' expects 4 bits on the Initial value, but Initial value's CONST '?32?bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' generates 32 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_lint_width_bad.v:17:25: Operator VAR 'XS' expects 4 bits on the Initial value, but Initial value's CONST '?32?bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' generates 32 bits. + : ... In instance t 17 | localparam [3:0] XS = 'hx; | ^~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. -%Warning-WIDTH: t/t_lint_width_bad.v:47:19: Operator ASSIGNW expects 5 bits on the Assign RHS, but Assign RHS's VARREF 'in' generates 4 bits. - : ... In instance t.p4 + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. +%Warning-WIDTHEXPAND: t/t_lint_width_bad.v:47:19: Operator ASSIGNW expects 5 bits on the Assign RHS, but Assign RHS's VARREF 'in' generates 4 bits. + : ... In instance t.p4 47 | wire [4:0] out = in; | ^ -%Warning-WIDTH: t/t_lint_width_bad.v:21:25: Operator SHIFTL expects 5 bits on the LHS, but LHS's CONST '1'h1' generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_lint_width_bad.v:21:25: Operator SHIFTL expects 5 bits on the LHS, but LHS's CONST '1'h1' generates 1 bits. + : ... In instance t 21 | wire [4:0] d = (1'b1 << 2) + 5'b1; | ^~ -%Warning-WIDTH: t/t_lint_width_bad.v:27:32: Operator ASSIGNW expects 6 bits on the Assign RHS, but Assign RHS's SHIFTL generates 7 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_lint_width_bad.v:27:32: Operator ASSIGNW expects 6 bits on the Assign RHS, but Assign RHS's SHIFTL generates 7 bits. + : ... In instance t 27 | wire [WIDTH-1:0] masked = (({{(WIDTH){1'b0}}, one_bit}) << shifter); | ^ -%Warning-WIDTH: t/t_lint_width_bad.v:32:37: Operator ADD expects 3 bits on the LHS, but LHS's VARREF 'one' generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_lint_width_bad.v:32:37: Operator ADD expects 3 bits on the LHS, but LHS's VARREF 'one' generates 1 bits. + : ... In instance t 32 | wire [2:0] cnt = (one + one + one + one); | ^ -%Warning-WIDTH: t/t_lint_width_bad.v:32:37: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_lint_width_bad.v:32:37: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. + : ... In instance t 32 | wire [2:0] cnt = (one + one + one + one); | ^ -%Warning-WIDTH: t/t_lint_width_bad.v:32:43: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_lint_width_bad.v:32:43: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. + : ... In instance t 32 | wire [2:0] cnt = (one + one + one + one); | ^ -%Warning-WIDTH: t/t_lint_width_bad.v:32:49: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_lint_width_bad.v:32:49: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits. + : ... In instance t 32 | wire [2:0] cnt = (one + one + one + one); | ^ -%Warning-WIDTH: t/t_lint_width_bad.v:37:26: Operator GT expects 41 bits on the LHS, but LHS's VARREF 'a' generates 32 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_lint_width_bad.v:37:26: Operator GT expects 41 bits on the LHS, but LHS's VARREF 'a' generates 32 bits. + : ... In instance t 37 | initial for (a = 0; a > THREE; ++a) $display(a); | ^ -%Warning-WIDTH: t/t_lint_width_bad.v:38:26: Operator GTE expects 41 bits on the LHS, but LHS's VARREF 'a' generates 32 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_lint_width_bad.v:38:26: Operator GTE expects 41 bits on the LHS, but LHS's VARREF 'a' generates 32 bits. + : ... In instance t 38 | initial for (a = 0; a >= THREE; ++a) $display(a); | ^~ -%Warning-WIDTH: t/t_lint_width_bad.v:40:12: Logical operator IF expects 1 bit on the If, but If's VARREF 'THREE' generates 41 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_lint_width_bad.v:40:12: Logical operator IF expects 1 bit on the If, but If's VARREF 'THREE' generates 41 bits. + : ... In instance t 40 | initial if (THREE) $stop; | ^~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_width_docs_bad.out b/test_regress/t/t_lint_width_docs_bad.out deleted file mode 100644 index 0ecd7edd9..000000000 --- a/test_regress/t/t_lint_width_docs_bad.out +++ /dev/null @@ -1,7 +0,0 @@ -%Warning-WIDTH: t/t_lint_width_docs_bad.v:10:29: Bit extraction of array[4:0] requires 3 bit index, not 2 bits. - : ... In instance t - 10 | wire int rd_value = array[rd_addr]; - | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. -%Error: Exiting due to diff --git a/test_regress/t/t_lint_width_genfor_bad.out b/test_regress/t/t_lint_width_genfor_bad.out index e94e66164..4e672b104 100644 --- a/test_regress/t/t_lint_width_genfor_bad.out +++ b/test_regress/t/t_lint_width_genfor_bad.out @@ -1,23 +1,23 @@ -%Warning-WIDTH: t/t_lint_width_genfor_bad.v:25:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's CONST '?32?sh10' generates 32 or 5 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:25:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's CONST '?32?sh10' generates 32 or 5 bits. + : ... In instance t 25 | rg = g; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. -%Warning-WIDTH: t/t_lint_width_genfor_bad.v:26:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'P' generates 32 or 5 bits. - : ... In instance t + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. +%Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:26:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'P' generates 32 or 5 bits. + : ... In instance t 26 | rp = P; | ^ -%Warning-WIDTH: t/t_lint_width_genfor_bad.v:27:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'w' generates 5 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:27:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'w' generates 5 bits. + : ... In instance t 27 | rw = w; | ^ -%Warning-WIDTH: t/t_lint_width_genfor_bad.v:28:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:28:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits. + : ... In instance t 28 | rc = 64'h1; | ^ -%Warning-WIDTH: t/t_lint_width_genfor_bad.v:33:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'i' generates 32 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_lint_width_genfor_bad.v:33:13: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's VARREF 'i' generates 32 bits. + : ... In instance t 33 | ri = i; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_lint_widthexpand_docs_bad.out b/test_regress/t/t_lint_widthexpand_docs_bad.out new file mode 100644 index 000000000..241fa51ce --- /dev/null +++ b/test_regress/t/t_lint_widthexpand_docs_bad.out @@ -0,0 +1,7 @@ +%Warning-WIDTHEXPAND: t/t_lint_widthexpand_docs_bad.v:10:29: Bit extraction of array[4:0] requires 3 bit index, not 2 bits. + : ... In instance t + 10 | wire int rd_value = array[rd_addr]; + | ^ + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. +%Error: Exiting due to diff --git a/test_regress/t/t_lint_width_docs_bad.pl b/test_regress/t/t_lint_widthexpand_docs_bad.pl similarity index 84% rename from test_regress/t/t_lint_width_docs_bad.pl rename to test_regress/t/t_lint_widthexpand_docs_bad.pl index 1afe476b9..a8b6a6651 100755 --- a/test_regress/t/t_lint_width_docs_bad.pl +++ b/test_regress/t/t_lint_widthexpand_docs_bad.pl @@ -18,18 +18,18 @@ lint( extract( in => $Self->{top_filename}, - out => "../docs/gen/ex_WIDTH_1_faulty.rst", + out => "../docs/gen/ex_WIDTHEXPAND_1_faulty.rst", lines => "8-10"); extract( in => $Self->{golden_filename}, - out => "../docs/gen/ex_WIDTH_1_msg.rst", + out => "../docs/gen/ex_WIDTHEXPAND_1_msg.rst", lineno_adjust => -7, regexp => qr/Warning-WIDTH/); extract( in => $Self->{top_filename}, - out => "../docs/gen/ex_WIDTH_1_fixed.rst", + out => "../docs/gen/ex_WIDTHEXPAND_1_fixed.rst", lines => "18"); ok(1); diff --git a/test_regress/t/t_lint_width_docs_bad.v b/test_regress/t/t_lint_widthexpand_docs_bad.v similarity index 100% rename from test_regress/t/t_lint_width_docs_bad.v rename to test_regress/t/t_lint_widthexpand_docs_bad.v diff --git a/test_regress/t/t_mailbox_std.pl b/test_regress/t/t_mailbox_std.pl index 54f95ce97..1229e6524 100755 --- a/test_regress/t/t_mailbox_std.pl +++ b/test_regress/t/t_mailbox_std.pl @@ -17,7 +17,7 @@ else { top_filename("t/t_mailbox.v"); compile( - verilator_flags2 => ["--exe --main --timing -Wall -DMAILBOX_T=std::mailbox"], + verilator_flags2 => ["--exe --main --timing -Wall --Wpedantic -DMAILBOX_T=std::mailbox"], make_main => 0, ); diff --git a/test_regress/t/t_math_countbits_bad.out b/test_regress/t/t_math_countbits_bad.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_math_imm2.cpp b/test_regress/t/t_math_imm2.cpp index b4c8015a0..3b2183cba 100644 --- a/test_regress/t/t_math_imm2.cpp +++ b/test_regress/t/t_math_imm2.cpp @@ -19,7 +19,7 @@ int main(int argc, char* argv[]) { Verilated::debug(0); Verilated::commandArgs(argc, argv); - Vt_math_imm2* sim = new Vt_math_imm2; + VM_PREFIX* sim = new VM_PREFIX; int lbit, hbit; int errs = 0; diff --git a/test_regress/t/t_math_real.v b/test_regress/t/t_math_real.v index 856547a66..8798f1cdb 100644 --- a/test_regress/t/t_math_real.v +++ b/test_regress/t/t_math_real.v @@ -6,7 +6,9 @@ // Version 2.0. // SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define stop $stop +`define checkr(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); `define is_near_real(a,b) (( ((a)<(b)) ? (b)-(a) : (a)-(b)) < (((a)/(b))*0.0001)) module t (/*AUTOARG*/ @@ -29,6 +31,7 @@ module t (/*AUTOARG*/ reg signed [95:0] cis96; real r, r2; integer cyc = 0; + string s; realtime uninit; initial if (uninit != 0.0) $stop; @@ -134,6 +137,22 @@ module t (/*AUTOARG*/ if (r != 74276402357122816493947453440.0) $stop; r = real'(96'shf0000000_00000000_00000000); if (r != -4951760157141521099596496896.0) $stop; + + r = 1.23456; + s = $sformatf("%g", r); + `checks(s, "1.23456"); + r = 1.0/0; // inf + s = $sformatf("%g", r); + `checks(s, "inf"); + r = -1.0/0; // -inf + s = $sformatf("%g", r); + `checks(s, "-inf"); + r = $sqrt(-1.0); // NaN + s = $sformatf("%g", r); + `checks(s, "-nan"); + r = -$sqrt(-1.0); // NaN + s = $sformatf("%g", r); + `checks(s, "nan"); end // Test loop diff --git a/test_regress/t/t_math_repl2_bad.out b/test_regress/t/t_math_repl2_bad.out new file mode 100644 index 000000000..5d3ff0d0d --- /dev/null +++ b/test_regress/t/t_math_repl2_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_math_repl2_bad.v:28:30: More than a 16 Mbit replication, perhaps the replication factor was two's-complement negative: 4294967291 + : ... In instance t + 28 | out <= {{(P24 - P29){1'b0}}, in}; + | ^ +%Error: Internal Error: ../V3Number.h:#: `num` member accessed when data type is UNINITIALIZED diff --git a/test_regress/t/t_math_repl2_bad.pl b/test_regress/t/t_math_repl2_bad.pl new file mode 100755 index 000000000..9c9fb65a0 --- /dev/null +++ b/test_regress/t/t_math_repl2_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_math_repl2_bad.v b/test_regress/t/t_math_repl2_bad.v new file mode 100644 index 000000000..346dcebde --- /dev/null +++ b/test_regress/t/t_math_repl2_bad.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Outputs + out, + // Inputs + clk, in + ); + + parameter P32 = 32; + parameter P24 = 24; + localparam P29 = P24 + 5; + + input clk; + output reg [P24-1:0] out; + + input [P29 - 1:0] in; + + always @(posedge clk) begin + if (P29 >= P24) begin + out <= in[P29 - 1 -: P24]; + end + else begin + out <= {{(P24 - P29){1'b0}}, in}; + end + end +endmodule diff --git a/test_regress/t/t_math_repl_bad.out b/test_regress/t/t_math_repl_bad.out index 49249a807..18193afbe 100644 --- a/test_regress/t/t_math_repl_bad.out +++ b/test_regress/t/t_math_repl_bad.out @@ -2,12 +2,12 @@ : ... In instance t 12 | o = {0 {1'b1}}; | ^ -%Warning-WIDTH: t/t_math_repl_bad.v:12:9: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's REPLICATE generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_math_repl_bad.v:12:9: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's REPLICATE generates 1 bits. + : ... In instance t 12 | o = {0 {1'b1}}; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error: t/t_math_repl_bad.v:13:12: Expecting expression to be constant, but can't convert a TESTPLUSARGS to constant. : ... In instance t 13 | o = {$test$plusargs("NON-CONSTANT") {1'b1}}; diff --git a/test_regress/t/t_mem_slot.cpp b/test_regress/t/t_mem_slot.cpp index a65ae687d..dfaee4052 100644 --- a/test_regress/t/t_mem_slot.cpp +++ b/test_regress/t/t_mem_slot.cpp @@ -48,7 +48,7 @@ int main(int argc, char* argv[]) { Verilated::debug(0); Verilated::commandArgs(argc, argv); - Vt_mem_slot* sim = new Vt_mem_slot; + VM_PREFIX* sim = new VM_PREFIX; int slot, bit, i; // clear all bits in the array diff --git a/test_regress/t/t_metacmt_onoff.out b/test_regress/t/t_metacmt_onoff.out index f57aee5e4..4c6ca3bf2 100644 --- a/test_regress/t/t_metacmt_onoff.out +++ b/test_regress/t/t_metacmt_onoff.out @@ -1,10 +1,10 @@ -%Warning-LITENDIAN: t/t_metacmt_onoff.v:8:8: Little bit endian vector: left < right of bit range: [0:1] +%Warning-LITENDIAN: t/t_metacmt_onoff.v:8:8: Big bit endian vector: left < right of bit range: [0:1] : ... In instance t 8 | reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3; | ^ ... For warning description see https://verilator.org/warn/LITENDIAN?v=latest ... Use "/* verilator lint_off LITENDIAN */" and lint_on around source to disable this message. -%Warning-LITENDIAN: t/t_metacmt_onoff.v:8:109: Little bit endian vector: left < right of bit range: [0:3] +%Warning-LITENDIAN: t/t_metacmt_onoff.v:8:109: Big bit endian vector: left < right of bit range: [0:3] : ... In instance t 8 | reg [0:1] show1; /*verilator lint_off LITENDIAN*/ reg [0:2] ign2; /*verilator lint_on LITENDIAN*/ reg [0:3] show3; | ^ diff --git a/test_regress/t/t_multitop_sig.cpp b/test_regress/t/t_multitop_sig.cpp index 29a01491b..b9bb8cfb0 100644 --- a/test_regress/t/t_multitop_sig.cpp +++ b/test_regress/t/t_multitop_sig.cpp @@ -23,7 +23,7 @@ int main(int argc, char* argv[]) { Verilated::debug(0); Verilated::commandArgs(argc, argv); - Vt_multitop_sig* topp = new Vt_multitop_sig{""}; + VM_PREFIX* topp = new VM_PREFIX{""}; { topp->a__02Ein = 0; diff --git a/test_regress/t/t_net_delay.out b/test_regress/t/t_net_delay.out index b11072c2e..afade27cb 100644 --- a/test_regress/t/t_net_delay.out +++ b/test_regress/t/t_net_delay.out @@ -1,7 +1,15 @@ +%Warning-STMTDLY: t/t_net_delay.v:13:14: Ignoring delay on this statement due to --no-timing + : ... In instance t + 13 | wire[3:0] #4 val1 = cyc; + | ^ + ... For warning description see https://verilator.org/warn/STMTDLY?v=latest + ... Use "/* verilator lint_off STMTDLY */" and lint_on around source to disable this message. +%Warning-STMTDLY: t/t_net_delay.v:14:14: Ignoring delay on this statement due to --no-timing + : ... In instance t + 14 | wire[3:0] #4 val2; + | ^ %Warning-ASSIGNDLY: t/t_net_delay.v:17:11: Ignoring timing control on this assignment/primitive due to --no-timing : ... In instance t 17 | assign #4 val2 = cyc; | ^ - ... For warning description see https://verilator.org/warn/ASSIGNDLY?v=latest - ... Use "/* verilator lint_off ASSIGNDLY */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_nettype.out b/test_regress/t/t_nettype.out new file mode 100644 index 000000000..6811cc566 --- /dev/null +++ b/test_regress/t/t_nettype.out @@ -0,0 +1,11 @@ +%Error-UNSUPPORTED: t/t_nettype.v:24:4: Unsupported: nettype + 24 | nettype real real1_n with Pkg::resolver; + | ^~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_nettype.v:28:4: Unsupported: nettype + 28 | nettype real real2_n with local_resolver; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_nettype.v:33:4: Unsupported: nettype + 33 | nettype real2_n real3_n; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_nettype.pl b/test_regress/t/t_nettype.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_nettype.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_nettype.v b/test_regress/t/t_nettype.v new file mode 100644 index 000000000..312a5960f --- /dev/null +++ b/test_regress/t/t_nettype.v @@ -0,0 +1,50 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +package Pkg; + real last_resolve; + + function automatic real resolver(input real drivers[]); + resolver = 0.0; + foreach (drivers[i]) resolver += drivers[i]; + last_resolve = resolver; + endfunction +endpackage + +module t(/*AUTOARG*/); + + function automatic real local_resolver(input real drivers[]); + local_resolver = 0.0; + foreach (drivers[i]) local_resolver += drivers[i]; + endfunction + + nettype real real1_n with Pkg::resolver; + real1_n real1; + assign real1 = 1.23; + + nettype real real2_n with local_resolver; + real2_n real2; + assign real2 = 1.23; + + // Create alias using new name + nettype real2_n real3_n; + real3_n real3; + assign real3 = 1.23; + + // TODO when implement net types need to check multiple driver cases, across + // submodules + + initial begin + #10; + if (real1 != 1.23) $stop; + if (real2 != 1.23) $stop; + if (real3 != 1.23) $stop; + if (Pkg::last_resolve != 1.23) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_no_std_bad.out b/test_regress/t/t_no_std_bad.out new file mode 100644 index 000000000..27e18ab7f --- /dev/null +++ b/test_regress/t/t_no_std_bad.out @@ -0,0 +1,8 @@ +%Error-PKGNODECL: t/t_no_std_bad.v:9:11: Package/class 'std' not found, and needs to be predeclared (IEEE 1800-2017 26.3) + 9 | import std::*; + | ^~~ + ... For error description see https://verilator.org/warn/PKGNODECL?v=latest +%Error: t/t_no_std_bad.v:9:11: Importing from missing package 'std' + 9 | import std::*; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_no_std_bad.pl b/test_regress/t/t_no_std_bad.pl new file mode 100755 index 000000000..b7236cf3c --- /dev/null +++ b/test_regress/t/t_no_std_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +lint(fails => 1, + verilator_flags2 => ["--no-std", "--exe --main --timing -Wall"], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_no_std_bad.v b/test_regress/t/t_no_std_bad.v new file mode 100644 index 000000000..3dbac71e6 --- /dev/null +++ b/test_regress/t/t_no_std_bad.v @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// verilator lint_off DECLFILENAME +module t(/*AUTOARG*/); + import std::*; +endmodule diff --git a/test_regress/t/t_opt_table_sparse_output_split.pl b/test_regress/t/t_opt_table_sparse_output_split.pl index a88e82fbd..f451aeecb 100755 --- a/test_regress/t/t_opt_table_sparse_output_split.pl +++ b/test_regress/t/t_opt_table_sparse_output_split.pl @@ -23,7 +23,7 @@ if ($Self->{vlt_all}) { } # Splitting should set VM_PARALLEL_BUILDS to 1 by default -file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}_classes.mk", qr/VM_PARALLEL_BUILDS\s*=\s*1/); +file_grep("$Self->{obj_dir}/$Self->{vm_prefix}_classes.mk", qr/VM_PARALLEL_BUILDS\s*=\s*1/); check_splits(2); diff --git a/test_regress/t/t_optm_if_array.pl b/test_regress/t/t_optm_if_array.pl index caf3de14b..482484eb4 100755 --- a/test_regress/t/t_optm_if_array.pl +++ b/test_regress/t/t_optm_if_array.pl @@ -17,7 +17,7 @@ execute( check_finished => 1, ); -for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root*.cpp")) { +for my $file (glob_all("$Self->{obj_dir}/$Self->{vm_prefix}___024root*.cpp")) { file_grep_not($file, qr/rstn_r/); } diff --git a/test_regress/t/t_optm_redor.pl b/test_regress/t/t_optm_redor.pl index caf3de14b..482484eb4 100755 --- a/test_regress/t/t_optm_redor.pl +++ b/test_regress/t/t_optm_redor.pl @@ -17,7 +17,7 @@ execute( check_finished => 1, ); -for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root*.cpp")) { +for my $file (glob_all("$Self->{obj_dir}/$Self->{vm_prefix}___024root*.cpp")) { file_grep_not($file, qr/rstn_r/); } diff --git a/test_regress/t/t_order_dpi_export_1.cpp b/test_regress/t/t_order_dpi_export_1.cpp index 7a261f661..2902ae32f 100644 --- a/test_regress/t/t_order_dpi_export_1.cpp +++ b/test_regress/t/t_order_dpi_export_1.cpp @@ -14,7 +14,7 @@ #include int main(int argc, char* argv[]) { - Vt_order_dpi_export_1* const tb = new Vt_order_dpi_export_1; + VM_PREFIX* const tb = new VM_PREFIX; tb->contextp()->commandArgs(argc, argv); bool clk = true; diff --git a/test_regress/t/t_order_dpi_export_2.cpp b/test_regress/t/t_order_dpi_export_2.cpp index fb134ddeb..ca68903cd 100644 --- a/test_regress/t/t_order_dpi_export_2.cpp +++ b/test_regress/t/t_order_dpi_export_2.cpp @@ -16,7 +16,7 @@ void toggle_other_clk(svBit val) { set_other_clk(val); } int main(int argc, char* argv[]) { - Vt_order_dpi_export_2* const tb = new Vt_order_dpi_export_2; + VM_PREFIX* const tb = new VM_PREFIX; tb->contextp()->commandArgs(argc, argv); bool clk = true; diff --git a/test_regress/t/t_order_dpi_export_3.cpp b/test_regress/t/t_order_dpi_export_3.cpp index c8a5fcb25..46087bafe 100644 --- a/test_regress/t/t_order_dpi_export_3.cpp +++ b/test_regress/t/t_order_dpi_export_3.cpp @@ -18,7 +18,7 @@ void toggle_other_clk(svBit val) { set_other_clk(val); } void toggle_third_clk(svBit val) { set_third_clk(val); } int main(int argc, char* argv[]) { - Vt_order_dpi_export_3* const tb = new Vt_order_dpi_export_3; + VM_PREFIX* const tb = new VM_PREFIX; tb->contextp()->commandArgs(argc, argv); bool clk = true; diff --git a/test_regress/t/t_order_dpi_export_4.cpp b/test_regress/t/t_order_dpi_export_4.cpp index 95c169f47..370bdb1c5 100644 --- a/test_regress/t/t_order_dpi_export_4.cpp +++ b/test_regress/t/t_order_dpi_export_4.cpp @@ -18,7 +18,7 @@ void toggle_other_clk(svBit val) { set_other_clk(val); } void toggle_third_clk(svBit val) { set_third_clk(val); } int main(int argc, char* argv[]) { - Vt_order_dpi_export_4* const tb = new Vt_order_dpi_export_4; + VM_PREFIX* const tb = new VM_PREFIX; tb->contextp()->commandArgs(argc, argv); bool clk = true; diff --git a/test_regress/t/t_order_dpi_export_5.cpp b/test_regress/t/t_order_dpi_export_5.cpp index 494b161a8..e043b2bd0 100644 --- a/test_regress/t/t_order_dpi_export_5.cpp +++ b/test_regress/t/t_order_dpi_export_5.cpp @@ -14,7 +14,7 @@ #include int main(int argc, char* argv[]) { - Vt_order_dpi_export_5* const tb = new Vt_order_dpi_export_5; + VM_PREFIX* const tb = new VM_PREFIX; tb->contextp()->commandArgs(argc, argv); bool clk = true; diff --git a/test_regress/t/t_order_dpi_export_6.cpp b/test_regress/t/t_order_dpi_export_6.cpp index 95fceb8ef..048447f2c 100644 --- a/test_regress/t/t_order_dpi_export_6.cpp +++ b/test_regress/t/t_order_dpi_export_6.cpp @@ -16,7 +16,7 @@ void toggle_other_clk(svBit val) { set_other_clk(val); } int main(int argc, char* argv[]) { - Vt_order_dpi_export_6* const tb = new Vt_order_dpi_export_6; + VM_PREFIX* const tb = new VM_PREFIX; tb->contextp()->commandArgs(argc, argv); bool clk = true; diff --git a/test_regress/t/t_order_dpi_export_7.cpp b/test_regress/t/t_order_dpi_export_7.cpp index 6034549d4..0649d2e97 100644 --- a/test_regress/t/t_order_dpi_export_7.cpp +++ b/test_regress/t/t_order_dpi_export_7.cpp @@ -14,7 +14,7 @@ #include int main(int argc, char* argv[]) { - Vt_order_dpi_export_7* const tb = new Vt_order_dpi_export_7; + VM_PREFIX* const tb = new VM_PREFIX; tb->contextp()->commandArgs(argc, argv); bool clk = true; diff --git a/test_regress/t/t_param_array3.v b/test_regress/t/t_param_array3.v index 3d9d98fb1..667276578 100644 --- a/test_regress/t/t_param_array3.v +++ b/test_regress/t/t_param_array3.v @@ -18,12 +18,18 @@ module t; endfunction parameter int SUMS[3:0] = calc_sums(); + parameter int SUMS1[3:0] = calc_sums(); initial begin if (SUMS[0] != 4) $stop; if (SUMS[1] != 4+3) $stop; if (SUMS[2] != 4+3+2) $stop; if (SUMS[3] != 4+3+2+1) $stop; + // According to section 13.4.3 of IEEE Std 1800-2017, + // execution at elaboration has no effect on the initial values + // of the variables used either at simulation time or among + // multiple invocations of a function at elaboration time + if (SUMS1 != SUMS) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_param_in_func.pl b/test_regress/t/t_param_in_func.pl index 849ab9a69..06352942b 100755 --- a/test_regress/t/t_param_in_func.pl +++ b/test_regress/t/t_param_in_func.pl @@ -23,8 +23,8 @@ if ($Self->{vlt_all}) { # Shouldn't have any references to the parameter array foreach my $file ( - glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.h"), - glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp") + glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.h"), + glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.cpp") ) { file_grep_not($file, qr/digits/i); } diff --git a/test_regress/t/t_param_in_func_noinline.pl b/test_regress/t/t_param_in_func_noinline.pl index c089b8b2e..3898be53f 100755 --- a/test_regress/t/t_param_in_func_noinline.pl +++ b/test_regress/t/t_param_in_func_noinline.pl @@ -25,8 +25,8 @@ if ($Self->{vlt_all}) { # Shouldn't have any references to the parameter array foreach my $file ( - glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.h"), - glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}*.cpp") + glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.h"), + glob_all("$Self->{obj_dir}/$Self->{vm_prefix}*.cpp") ) { file_grep_not($file, qr/digits/i); } diff --git a/test_regress/t/t_param_mintypmax.pl b/test_regress/t/t_param_mintypmax.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_param_mintypmax.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_mintypmax.v b/test_regress/t/t_param_mintypmax.v new file mode 100644 index 000000000..dd9acdb5a --- /dev/null +++ b/test_regress/t/t_param_mintypmax.v @@ -0,0 +1,17 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + parameter MTM = (1:2:3); + + initial begin + if (MTM != 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_param_module.v b/test_regress/t/t_param_module.v index 89d8e77bc..18369db2c 100644 --- a/test_regress/t/t_param_module.v +++ b/test_regress/t/t_param_module.v @@ -7,7 +7,7 @@ // used in the test module to set the value of MSB. A number of warnings and // errors follow, starting with: // -// %Warning-LITENDIAN: t/t_param_module.v:42: Little bit endian vector: MSB +// %Warning-LITENDIAN: t/t_param_module.v:42: Big bit endian vector: MSB // < LSB of bit range: -17:0 // // This file ONLY is placed into the Public Domain, for any use, without diff --git a/test_regress/t/t_param_noval_bad.out b/test_regress/t/t_param_noval_bad.out index 66b235cac..ff5b9a48f 100644 --- a/test_regress/t/t_param_noval_bad.out +++ b/test_regress/t/t_param_noval_bad.out @@ -2,12 +2,12 @@ : ... In instance t 7 | module t #(parameter P); | ^ -%Warning-WIDTH: t/t_param_noval_bad.v:10:7: Logical operator GENFOR expects 1 bit on the For Test Condition, but For Test Condition's VARREF 'P' generates 32 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_param_noval_bad.v:10:7: Logical operator GENFOR expects 1 bit on the For Test Condition, but For Test Condition's VARREF 'P' generates 32 bits. + : ... In instance t 10 | for (j=0; P; j++) | ^~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: t/t_param_noval_bad.v:10:7: Non-genvar used in generate for: 'j' : ... In instance t 10 | for (j=0; P; j++) diff --git a/test_regress/t/t_param_public.cpp b/test_regress/t/t_param_public.cpp index 17cc1c0f6..6bed53bd0 100644 --- a/test_regress/t/t_param_public.cpp +++ b/test_regress/t/t_param_public.cpp @@ -18,7 +18,7 @@ int main(int argc, char* argv[]) { Verilated::debug(0); Verilated::commandArgs(argc, argv); - Vt_param_public* topp = new Vt_param_public; + VM_PREFIX* topp = new VM_PREFIX; // Make sure public tag worked if (static_cast(Vt_param_public_t::TOP_PARAM) != 30) { diff --git a/test_regress/t/t_param_type5.pl b/test_regress/t/t_param_type5.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_param_type5.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_type5.v b/test_regress/t/t_param_type5.v new file mode 100644 index 000000000..cd73625c7 --- /dev/null +++ b/test_regress/t/t_param_type5.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class ParamClass #(string P = "ABC", R = "GDF"); +endclass + +module t #(parameter int A = 0, B = 1, C = 2, type D = int, E = string); + parameter bit F = 1'b0, G = 1'b1; + parameter type H = int, I = string; + E str1 = "abc"; + I str2 = ""; + initial begin + automatic ParamClass param_class = new; + if ($typename(B) != "int") $stop; + if ($typename(C) != "int") $stop; + if (str1.len() != 3) $stop; + if ($typename(G) != "bit") $stop; + if (str2.len() != 0) $stop; + if ($typename(param_class.R) != "string") $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_param_type_bit.pl b/test_regress/t/t_param_type_bit.pl new file mode 100755 index 000000000..552bd97db --- /dev/null +++ b/test_regress/t/t_param_type_bit.pl @@ -0,0 +1,17 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_type_bit.v b/test_regress/t/t_param_type_bit.v new file mode 100644 index 000000000..4317ee39d --- /dev/null +++ b/test_regress/t/t_param_type_bit.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This test examines Verilator against paramter definition with functions. +// Particularly the function takes in argument which is multi-dimentional. +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + sub sub(); +endmodule + +module sub + #(parameter type T = type(bit[9:0]) ) + (); + + type(bit[9:0]) tvar; + + initial begin + if ($bits(T) != 10) $stop; + if ($bits(tvar) != 10) $stop; + $finish; + end +endmodule diff --git a/test_regress/t/t_param_width_loc_bad.out b/test_regress/t/t_param_width_loc_bad.out index 3fed6e9b7..3905343e9 100644 --- a/test_regress/t/t_param_width_loc_bad.out +++ b/test_regress/t/t_param_width_loc_bad.out @@ -1,7 +1,7 @@ -%Warning-WIDTH: t/t_param_width_loc_bad.v:25:21: Operator VAR 'param' expects 1 bits on the Initial value, but Initial value's CONST '32'h0' generates 32 bits. - : ... In instance t.test_i +%Warning-WIDTHTRUNC: t/t_param_width_loc_bad.v:25:21: Operator VAR 'param' expects 1 bits on the Initial value, but Initial value's CONST '32'h0' generates 32 bits. + : ... In instance t.test_i 25 | parameter logic param = 1'b0 | ^~~~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_past_funcs.v b/test_regress/t/t_past_funcs.v index 2dce45368..74ba1dc76 100644 --- a/test_regress/t/t_past_funcs.v +++ b/test_regress/t/t_past_funcs.v @@ -23,6 +23,11 @@ module t (/*AUTOARG*/ .clk (clk), .in (in[31:0])); + Test3 test3 (/*AUTOINST*/ + // Inputs + .clk (clk), + .in (in[31:0])); + always @ (posedge clk) begin if (cyc!=0) begin cyc <= cyc + 1; @@ -69,6 +74,27 @@ module Test (/*AUTOARG*/ assert property (@(posedge clk) $fell(dly1) || dly1%2==1); assert property (@(posedge clk) !$stable(dly2)); assert property (@(posedge clk) $changed(dly2)); + + global clocking @(posedge clk); endclocking + always @ ($global_clock) $display("%d", in); + // + assert property (@(posedge clk) $rose(dly0, $global_clock) || dly0%2==0); + assert property (@(posedge clk) $fell(dly1, $global_clock) || dly1%2==1); + assert property (@(posedge clk) !$stable(dly2, $global_clock)); + assert property (@(posedge clk) $changed(dly2, $global_clock)); + // + assert property (@(posedge clk) $rose_gclk(dly0) || dly0%2==0); + assert property (@(posedge clk) $fell_gclk(dly1) || dly1%2==1); + assert property (@(posedge clk) !$stable_gclk(dly2)); + assert property (@(posedge clk) $changed_gclk(dly2)); + + // global_clocking_future_functions are not supported yet: + // $changing_gclk global_clocking_future_function + // $falling_gclk global_clocking_future_function + // $future_gclk global_clocking_future_function + // $rising_gclk global_clocking_future_function + // $steady_gclk global_clocking_future_function + endmodule @@ -101,3 +127,18 @@ module Test2 (/*AUTOARG*/ assert property ($stable(dly2[31:4])); assert property (!$changed(dly2[31:4])); endmodule + +module Test3 (/*AUTOARG*/ + // Inputs + clk, in + ); + + input clk; + input [31:0] in; + + // Check the named form of global clocking + global clocking gck @(posedge clk); endclocking + always @ (gck) $display("%d", in); + always @ ($global_clock) $display("%d", in); + +endmodule diff --git a/test_regress/t/t_past_unsup_bad.out b/test_regress/t/t_past_unsup_bad.out deleted file mode 100644 index e55f867f2..000000000 --- a/test_regress/t/t_past_unsup_bad.out +++ /dev/null @@ -1,20 +0,0 @@ -%Error-UNSUPPORTED: t/t_past_unsup_bad.v:13:11: Unsupported: $past expr2 and clock arguments - 13 | if ($past(d, 0, 0)) $stop; - | ^~~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_past_unsup_bad.v:14:11: Unsupported: $past expr2 and clock arguments - 14 | if ($past(d, 0, 0, clk)) $stop; - | ^~~~~ -%Error-UNSUPPORTED: t/t_past_unsup_bad.v:15:11: Unsupported: $fell and clock arguments - 15 | if ($fell(d, clk)) $stop; - | ^~~~~ -%Error-UNSUPPORTED: t/t_past_unsup_bad.v:16:11: Unsupported: $rose and clock arguments - 16 | if ($rose(d, clk)) $stop; - | ^~~~~ -%Error-UNSUPPORTED: t/t_past_unsup_bad.v:17:11: Unsupported: $stable and clock arguments - 17 | if ($stable(d, clk)) $stop; - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_past_unsup_bad.v:18:11: Unsupported: $changed and clock arguments - 18 | if ($changed(d, clk)) $stop; - | ^~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_past_unsup_bad.v b/test_regress/t/t_past_unsup_bad.v deleted file mode 100644 index edcc5c490..000000000 --- a/test_regress/t/t_past_unsup_bad.v +++ /dev/null @@ -1,20 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2018 by Wilson Snyder. -// SPDX-License-Identifier: CC0-1.0 - -module t (d, clk); - input d; - input clk; - - always @ (posedge clk) begin - // Unsupported - if ($past(d, 0, 0)) $stop; - if ($past(d, 0, 0, clk)) $stop; - if ($fell(d, clk)) $stop; - if ($rose(d, clk)) $stop; - if ($stable(d, clk)) $stop; - if ($changed(d, clk)) $stop; - end -endmodule diff --git a/test_regress/t/t_pgo_profoutofdate_bad.v b/test_regress/t/t_pgo_profoutofdate_bad.v old mode 100755 new mode 100644 diff --git a/test_regress/t/t_pkg_identifier_bad.out b/test_regress/t/t_pkg_identifier_bad.out new file mode 100644 index 000000000..2eef0f1ac --- /dev/null +++ b/test_regress/t/t_pkg_identifier_bad.out @@ -0,0 +1,5 @@ +%Error-PKGNODECL: t/t_pkg_identifier_bad.v:15:20: Package/class 'bar' not found, and needs to be predeclared (IEEE 1800-2017 26.3) + 15 | int baz = foo::bar::baz; + | ^~~ + ... For error description see https://verilator.org/warn/PKGNODECL?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_pkg_identifier_bad.pl b/test_regress/t/t_pkg_identifier_bad.pl new file mode 100755 index 000000000..376c2d2ee --- /dev/null +++ b/test_regress/t/t_pkg_identifier_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_pkg_identifier_bad.v b/test_regress/t/t_pkg_identifier_bad.v new file mode 100644 index 000000000..a3cd4a068 --- /dev/null +++ b/test_regress/t/t_pkg_identifier_bad.v @@ -0,0 +1,16 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +package foo; +endpackage + +package bar; + static int baz; +endpackage + +module t; + int baz = foo::bar::baz; +endmodule diff --git a/test_regress/t/t_preproc_cmtend_bad.pl b/test_regress/t/t_preproc_cmtend_bad.pl index a60503a1f..47d394e3b 100755 --- a/test_regress/t/t_preproc_cmtend_bad.pl +++ b/test_regress/t/t_preproc_cmtend_bad.pl @@ -12,6 +12,7 @@ scenarios(linter => 1); lint( fails => 1, + verilator_flags2 => ['--no-std'], expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_preproc_eof3_bad.pl b/test_regress/t/t_preproc_eof3_bad.pl index a60503a1f..47d394e3b 100755 --- a/test_regress/t/t_preproc_eof3_bad.pl +++ b/test_regress/t/t_preproc_eof3_bad.pl @@ -12,6 +12,7 @@ scenarios(linter => 1); lint( fails => 1, + verilator_flags2 => ['--no-std'], expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_preproc_kwd_bad.pl b/test_regress/t/t_preproc_kwd_bad.pl index 59ba0d6c6..47f9bc97a 100755 --- a/test_regress/t/t_preproc_kwd_bad.pl +++ b/test_regress/t/t_preproc_kwd_bad.pl @@ -12,6 +12,7 @@ scenarios(linter => 1); lint( fails => $Self->{vlt_all}, + verilator_flags2 => ['--no-std'], expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_process.out b/test_regress/t/t_process.out index a4ada3778..74d069569 100644 --- a/test_regress/t/t_process.out +++ b/test_regress/t/t_process.out @@ -1,10 +1,24 @@ +%Error: t/t_process.v:26:11: Forward typedef used as class/package does not resolve to class/package: 'process' + 26 | p = process::self(); + | ^~~~~~~ +%Error: t/t_process.v:27:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 27 | if (p.status() != process::RUNNING) $stop; + | ^~~~~~~ +%Error: t/t_process.v:28:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 28 | if (p.status() == process::WAITING) $stop; + | ^~~~~~~ +%Error: t/t_process.v:29:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 29 | if (p.status() == process::SUSPENDED) $stop; + | ^~~~~~~ +%Error: t/t_process.v:30:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 30 | if (p.status() == process::KILLED) $stop; + | ^~~~~~~ +%Error: t/t_process.v:31:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 31 | if (p.status() == process::FINISHED) $stop; + | ^~~~~~~ %Error: t/t_process.v:22:4: Can't find typedef: 'process' 22 | process p; | ^~~~~~~ -%Error-UNSUPPORTED: t/t_process.v:26:20: Unsupported: 'process' - 26 | p = process::self(); - | ^~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link 26 | p = process::self(); | ^~~~~~~ diff --git a/test_regress/t/t_process_bad.out b/test_regress/t/t_process_bad.out index 3a5b96793..3e6f927d1 100644 --- a/test_regress/t/t_process_bad.out +++ b/test_regress/t/t_process_bad.out @@ -1,10 +1,9 @@ +%Error: t/t_process_bad.v:12:11: Forward typedef used as class/package does not resolve to class/package: 'process' + 12 | p = process::self(); + | ^~~~~~~ %Error: t/t_process_bad.v:8:4: Can't find typedef: 'process' 8 | process p; | ^~~~~~~ -%Error-UNSUPPORTED: t/t_process_bad.v:12:20: Unsupported: 'process' - 12 | p = process::self(); - | ^~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Internal Error: t/t_process_bad.v:12:11: ../V3LinkDot.cpp:#: Bad package link 12 | p = process::self(); | ^~~~~~~ diff --git a/test_regress/t/t_process_std.out b/test_regress/t/t_process_std.out index a4ada3778..74d069569 100644 --- a/test_regress/t/t_process_std.out +++ b/test_regress/t/t_process_std.out @@ -1,10 +1,24 @@ +%Error: t/t_process.v:26:11: Forward typedef used as class/package does not resolve to class/package: 'process' + 26 | p = process::self(); + | ^~~~~~~ +%Error: t/t_process.v:27:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 27 | if (p.status() != process::RUNNING) $stop; + | ^~~~~~~ +%Error: t/t_process.v:28:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 28 | if (p.status() == process::WAITING) $stop; + | ^~~~~~~ +%Error: t/t_process.v:29:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 29 | if (p.status() == process::SUSPENDED) $stop; + | ^~~~~~~ +%Error: t/t_process.v:30:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 30 | if (p.status() == process::KILLED) $stop; + | ^~~~~~~ +%Error: t/t_process.v:31:25: Forward typedef used as class/package does not resolve to class/package: 'process' + 31 | if (p.status() == process::FINISHED) $stop; + | ^~~~~~~ %Error: t/t_process.v:22:4: Can't find typedef: 'process' 22 | process p; | ^~~~~~~ -%Error-UNSUPPORTED: t/t_process.v:26:20: Unsupported: 'process' - 26 | p = process::self(); - | ^~~~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest %Error: Internal Error: t/t_process.v:26:11: ../V3LinkDot.cpp:#: Bad package link 26 | p = process::self(); | ^~~~~~~ diff --git a/test_regress/t/t_prof.pl b/test_regress/t/t_prof.pl index 8601d6715..2d276ba37 100755 --- a/test_regress/t/t_prof.pl +++ b/test_regress/t/t_prof.pl @@ -36,7 +36,7 @@ sub dotest { $gmon_path or error("Profiler did not create a gmon.out"); (my $gmon_base = $gmon_path) =~ s!.*[/\\]!!; - run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.out"], + run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{vm_prefix} $gmon_base > gprof.out"], check_finished => 0); run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"], diff --git a/test_regress/t/t_profc.pl b/test_regress/t/t_profc.pl index ec6efa483..e972b9a9e 100755 --- a/test_regress/t/t_profc.pl +++ b/test_regress/t/t_profc.pl @@ -31,7 +31,7 @@ sub dotest { $gmon_path or error("Profiler did not create a gmon.out"); (my $gmon_base = $gmon_path) =~ s!.*[/\\]!!; - run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.out"], + run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{vm_prefix} $gmon_base > gprof.out"], check_finished => 0); } diff --git a/test_regress/t/t_protect_ids.pl b/test_regress/t/t_protect_ids.pl index c1b4a0455..06ec6487b 100755 --- a/test_regress/t/t_protect_ids.pl +++ b/test_regress/t/t_protect_ids.pl @@ -35,7 +35,7 @@ execute( # 'to="PS"' indicates means we probably mis-protected something already protected # Use --debug-protect to assist debugging these -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}__idmap.xml", qr/to="PS/); +file_grep_not("$Self->{obj_dir}/$Self->{vm_prefix}__idmap.xml", qr/to="PS/); if ($Self->{vlt_all}) { # Check for secret in any outputs diff --git a/test_regress/t/t_protect_ids_key.pl b/test_regress/t/t_protect_ids_key.pl index e1dd48942..8c38f80c2 100755 --- a/test_regress/t/t_protect_ids_key.pl +++ b/test_regress/t/t_protect_ids_key.pl @@ -22,7 +22,7 @@ execute( ); # Since using a named key, we can check for always identical map -files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__idmap.xml", $Self->{golden_filename}); +files_identical("$Self->{obj_dir}/$Self->{vm_prefix}__idmap.xml", $Self->{golden_filename}); ok(1); 1; diff --git a/test_regress/t/t_public_clk.cpp b/test_regress/t/t_public_clk.cpp index 7d27a83c8..3a76d1d7c 100644 --- a/test_regress/t/t_public_clk.cpp +++ b/test_regress/t/t_public_clk.cpp @@ -19,7 +19,7 @@ int main(int argc, char** argv) { contextp->debug(0); contextp->commandArgs(argc, argv); srand48(5); - topp.reset(new Vt_public_clk("top")); + topp.reset(new VM_PREFIX{"top"}); topp->rootp->t__DOT__clk = 0; topp->eval(); diff --git a/test_regress/t/t_public_seq.cpp b/test_regress/t/t_public_seq.cpp index 3299aba0c..beda4a7e3 100644 --- a/test_regress/t/t_public_seq.cpp +++ b/test_regress/t/t_public_seq.cpp @@ -19,7 +19,7 @@ int main(int argc, char** argv) { contextp->debug(0); contextp->commandArgs(argc, argv); srand48(5); - topp.reset(new Vt_public_seq("top")); + topp.reset(new VM_PREFIX{"top"}); topp->clk = 0; topp->eval(); diff --git a/test_regress/t/t_public_seq.v b/test_regress/t/t_public_seq.v index 007e51ffe..a796e15c2 100644 --- a/test_regress/t/t_public_seq.v +++ b/test_regress/t/t_public_seq.v @@ -37,6 +37,8 @@ module t ( end always_ff @(posedge dummy_clk) begin + // verilator lint_off MULTIDRIVEN comb_byte = ~pub_byte; + // verilator lint_on MULTIDRIVEN end endmodule diff --git a/test_regress/t/t_queue_empty_bad.out b/test_regress/t/t_queue_empty_bad.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_queue_init.pl b/test_regress/t/t_queue_init.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_queue_init.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_queue_init.v b/test_regress/t/t_queue_init.v new file mode 100644 index 000000000..cc22d9747 --- /dev/null +++ b/test_regress/t/t_queue_init.v @@ -0,0 +1,36 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) + +module t (/*AUTOARG*/); + + int a1[$] = '{12, 13}; + int a2[$] = {14, 15}; + int a3[$] = '{16}; + int a4[$] = {17}; + + initial begin + `checkh(a1.size, 2); + `checkh(a1[0], 12); + `checkh(a1[1], 13); + + `checkh(a2.size, 2); + `checkh(a2[0], 14); + `checkh(a2[1], 15); + + `checkh(a3.size, 1); + `checkh(a3[0], 16); + + `checkh(a4.size, 1); + `checkh(a4[0], 17); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_queue_method2_bad.out b/test_regress/t/t_queue_method2_bad.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_queue_method_bad.out b/test_regress/t/t_queue_method_bad.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_randcase_bad.out b/test_regress/t/t_randcase_bad.out index fa2e9ec7f..4e3daeeac 100644 --- a/test_regress/t/t_randcase_bad.out +++ b/test_regress/t/t_randcase_bad.out @@ -1 +1,2 @@ [0] %Error: t_randcase_bad.v:12: Assertion failed in top.t.unnamedblk1: All randcase items had 0 weights (IEEE 1800-2017 18.16) +*-* All Finished *-* diff --git a/test_regress/t/t_randcase_bad.v b/test_regress/t/t_randcase_bad.v index a299b04e1..4704bf681 100644 --- a/test_regress/t/t_randcase_bad.v +++ b/test_regress/t/t_randcase_bad.v @@ -12,6 +12,7 @@ module t (/*AUTOARG*/); randcase // Bad all zero weights 0 : $stop; endcase + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_randomize.out b/test_regress/t/t_randomize.out index e46ab03c5..334f02e8a 100644 --- a/test_regress/t/t_randomize.out +++ b/test_regress/t/t_randomize.out @@ -8,4 +8,10 @@ %Error-UNSUPPORTED: t/t_randomize.v:32:9: Unsupported: dist 32 | x dist { [100:102] :/ 1, 200 := 2, 300 := 5, 400}; | ^~~~ +%Error-UNSUPPORTED: t/t_randomize.v:37:1: Unsupported: extern constraint + 37 | constraint Packet::ex { header > 0 }; + | ^~~~~~~~~~ +%Error: t/t_randomize.v:37:23: syntax error, unexpected '{' + 37 | constraint Packet::ex { header > 0 }; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_randomize.v b/test_regress/t/t_randomize.v index 9c3d9bf5e..30634b113 100644 --- a/test_regress/t/t_randomize.v +++ b/test_regress/t/t_randomize.v @@ -16,14 +16,14 @@ class Packet; header < (64'h1 << length); } } - constraint b { + constraint c { header >= length - 10; header <= length; } - constraint c { + constraint d { foreach (in_use[i]) { !(start_offset <= in_use[i].Xend_offsetX && - start_offset + len - 1 >= in_use[i].Xstart_offsetX); + start_offset + length - 1 >= in_use[i].Xstart_offsetX); } } constraint order { solve length before header; } @@ -34,6 +34,8 @@ class Packet; endclass +constraint Packet::ex { header > 0 }; + module t (/*AUTOARG*/); Packet p; diff --git a/test_regress/t/t_randsequence.out b/test_regress/t/t_randsequence.out new file mode 100644 index 000000000..55a2a3289 --- /dev/null +++ b/test_regress/t/t_randsequence.out @@ -0,0 +1,152 @@ +%Error-UNSUPPORTED: t/t_randsequence.v:23:17: Unsupported: randsequence production id + 23 | main : one; + | ^~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_randsequence.v:23:15: Unsupported: randsequence production + 23 | main : one; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:24:14: Unsupported: randsequence production + 24 | one : { o = 1; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:22:7: Unsupported: randsequence + 22 | randsequence(main) + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:40:16: Unsupported: randsequence production id + 40 | main: one two three; + | ^~~ +%Error-UNSUPPORTED: t/t_randsequence.v:40:20: Unsupported: randsequence production id + 40 | main: one two three; + | ^~~ +%Error-UNSUPPORTED: t/t_randsequence.v:40:24: Unsupported: randsequence production id + 40 | main: one two three; + | ^~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:40:14: Unsupported: randsequence production + 40 | main: one two three; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:41:13: Unsupported: randsequence production + 41 | two: { do if ((seq) !== (1)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", "t/t_randsequence.v",41, (seq), (1)); $stop; end while(0);; seq = 2; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:42:13: Unsupported: randsequence production + 42 | one: { do if ((seq) !== (0)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", "t/t_randsequence.v",42, (seq), (0)); $stop; end while(0);; seq = 1; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:43:15: Unsupported: randsequence production + 43 | three: { do if ((seq) !== (2)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", "t/t_randsequence.v",43, (seq), (2)); $stop; end while(0);; seq = 3; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:39:7: Unsupported: randsequence + 39 | randsequence(main) + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:51:17: Unsupported: randsequence production + 51 | unnamed: { seq = 2; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:50:7: Unsupported: randsequence + 50 | randsequence() + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:58:17: Unsupported: randsequence production + 58 | unnamed: { }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:57:7: Unsupported: randsequence + 57 | randsequence() + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:65:19: Unsupported: randsequence production id + 65 | main: one | two | three := 2; + | ^~~ +%Error-UNSUPPORTED: t/t_randsequence.v:65:25: Unsupported: randsequence production id + 65 | main: one | two | three := 2; + | ^~~ +%Error-UNSUPPORTED: t/t_randsequence.v:65:31: Unsupported: randsequence production id + 65 | main: one | two | three := 2; + | ^~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:65:31: Unsupported: randsequence rule + 65 | main: one | two | three := 2; + | ^~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:65:17: Unsupported: randsequence production + 65 | main: one | two | three := 2; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:66:16: Unsupported: randsequence production + 66 | one: { ++counts[0]; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:67:16: Unsupported: randsequence production + 67 | two: { ++counts[1]; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:68:18: Unsupported: randsequence production + 68 | three: { ++counts[2]; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:64:10: Unsupported: randsequence + 64 | randsequence(main) + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:79:19: Unsupported: randsequence production id + 79 | main: one_if; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:79:17: Unsupported: randsequence production + 79 | main: one_if; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:80:38: Unsupported: randsequence production id + 80 | one_if: if (i % 10 == 0) count_1 else most; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:80:51: Unsupported: randsequence production id + 80 | one_if: if (i % 10 == 0) count_1 else most; + | ^~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:80:21: Unsupported: randsequence if + 80 | one_if: if (i % 10 == 0) count_1 else most; + | ^~ +%Error-UNSUPPORTED: t/t_randsequence.v:80:19: Unsupported: randsequence production + 80 | one_if: if (i % 10 == 0) count_1 else most; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:81:20: Unsupported: randsequence production + 81 | count_1: { ++counts[1]; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:82:20: Unsupported: randsequence production + 82 | count_2: { ++counts[2]; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:83:20: Unsupported: randsequence production + 83 | count_3: { ++counts[3]; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:84:20: Unsupported: randsequence production + 84 | count_4: { ++counts[4]; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:85:16: Unsupported: randsequence production + 85 | bad: { $stop; }; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:87:24: Unsupported: randsequence production id + 87 | 0: bad; + | ^~~ +%Error-UNSUPPORTED: t/t_randsequence.v:87:22: Unsupported: randsequence case item + 87 | 0: bad; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:88:27: Unsupported: randsequence production id + 88 | 1, 2: count_2; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:88:25: Unsupported: randsequence case item + 88 | 1, 2: count_2; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:89:30: Unsupported: randsequence production id + 89 | 3, 4, 5: count_3; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:89:28: Unsupported: randsequence case item + 89 | 3, 4, 5: count_3; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:90:30: Unsupported: randsequence production id + 90 | default: count_4; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:90:21: Unsupported: randsequence case item + 90 | default: count_4; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:86:19: Unsupported: randsequence case + 86 | most: case (i % 10) + | ^~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:86:17: Unsupported: randsequence production + 86 | most: case (i % 10) + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:78:10: Unsupported: randsequence + 78 | randsequence(main) + | ^~~~~~~~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:103:19: Unsupported: randsequence production id + 103 | main: one_if; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_randsequence.v:103:17: Unsupported: randsequence production + 103 | main: one_if; + | ^ +%Error-UNSUPPORTED: t/t_randsequence.v:104:38: Unsupported: randsequence production id + 104 | one_if: if (i % 10 == 0) count_1 else most; + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_randsequence.pl b/test_regress/t/t_randsequence.pl new file mode 100755 index 000000000..b003e3144 --- /dev/null +++ b/test_regress/t/t_randsequence.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_randsequence.v b/test_regress/t/t_randsequence.v new file mode 100644 index 000000000..3bd4fbad2 --- /dev/null +++ b/test_regress/t/t_randsequence.v @@ -0,0 +1,217 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2023 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +`define check_range(gotv,minv,maxv) do if ((gotv) < (minv) || (gotv) > (maxv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d-%0d\n", `__FILE__,`__LINE__, (gotv), (minv), (maxv)); $stop; end while(0); +`define check_within_30_percent(gotv,val) `check_range((gotv), (val) * 70 / 100, (val) * 130 / 100) + +module t(/*AUTOARG*/); + + localparam int COUNT = 1000; + + int seq; + int counts[8]; + + function automatic int sfunc(); + int o = 2; + randsequence(main) + main : one; + one : { o = 1; }; + endsequence + return o; + endfunction + + task prep(); + for (int i = 0; i < COUNT; ++i) counts[i] = 0; + endtask + + initial begin; + if (sfunc() != 1) $stop; + + // simple + prep(); + seq = 0; + randsequence(main) + main: one two three; + two: { `checkd(seq, 1); seq = 2; }; + one: { `checkd(seq, 0); seq = 1; }; + three: { `checkd(seq, 2); seq = 3; }; + endsequence + `checkd(seq, 3); + + // simple unnamed + prep(); + seq = 0; + randsequence() + unnamed: { seq = 2; }; + endsequence + `checkd(seq, 2); + + // empty block + prep(); + randsequence() + unnamed: { }; + endsequence + + // weight + prep(); + for (int i = 0; i < COUNT; ++i) begin + randsequence(main) + main: one | two | three := 2; + one: { ++counts[0]; }; + two: { ++counts[1]; }; + three: { ++counts[2]; }; + endsequence + end + `check_within_30_percent(counts[0], COUNT * 1 / 4); + `check_within_30_percent(counts[1], COUNT * 1 / 4); + `check_within_30_percent(counts[2], COUNT * 2 / 4); + + // case + prep(); + for (int i = 0; i < COUNT; ++i) begin + randsequence(main) + main: one_if; + one_if: if (i % 10 == 0) count_1 else most; + count_1: { ++counts[1]; }; + count_2: { ++counts[2]; }; + count_3: { ++counts[3]; }; + count_4: { ++counts[4]; }; + bad: { $stop; }; + most: case (i % 10) + 0: bad; + 1, 2: count_2; + 3, 4, 5: count_3; + default: count_4; + endcase; + endsequence + end + `check_within_30_percent(counts[1], COUNT * 1 / 10); + `check_within_30_percent(counts[2], COUNT * 2 / 10); + `check_within_30_percent(counts[3], COUNT * 3 / 10); + `check_within_30_percent(counts[4], COUNT * 4 / 10); + + // case - different default + prep(); + for (int i = 0; i < COUNT; ++i) begin + randsequence(main) + main: one_if; + one_if: if (i % 10 == 0) count_1 else most; + count_1: { ++counts[1]; }; + count_2: { ++counts[2]; }; + count_3: { ++counts[3]; }; + count_4: { ++counts[4]; }; + bad: { $stop; }; + most: case (i % 10) + 0: bad; + 1, 2: count_2; + 3, 4, 5: count_3; + default count_4; // No : + endcase; + endsequence + end + `check_within_30_percent(counts[1], COUNT * 1 / 10); + `check_within_30_percent(counts[2], COUNT * 2 / 10); + `check_within_30_percent(counts[3], COUNT * 3 / 10); + `check_within_30_percent(counts[4], COUNT * 4 / 10); + + // repeat + prep(); + randsequence(main) + main: repeat(10) count_1; + count_1: { ++counts[1]; }; + endsequence + `checkd(counts[1], 10); + + // rand join + prep(); + for (int i = 0; i < COUNT; ++i) begin + randsequence(main) + main: rand join count_1 count_2; + count_1: { ++counts[1]; }; + count_2: { ++counts[2]; }; + endsequence + end + `check_within_30_percent(counts[1], COUNT * 1 / 1); + `check_within_30_percent(counts[2], COUNT * 1 / 1); + + // rand join weight (TODO weight not tested yet) + prep(); + for (int i = 0; i < COUNT; ++i) begin + randsequence(main) + main: rand join (1.0) count_1 count_2; + count_1: { ++counts[1]; }; + count_2: { ++counts[2]; }; + endsequence + randsequence(main) + main: rand join (0.0) count_3 count_4; + count_3: { ++counts[3]; }; + count_4: { ++counts[4]; }; + endsequence + end + `check_within_30_percent(counts[1], COUNT * 1 / 1); + `check_within_30_percent(counts[2], COUNT * 1 / 1); + `check_within_30_percent(counts[3], COUNT * 1 / 1); + `check_within_30_percent(counts[4], COUNT * 1 / 1); + + // break + prep(); + for (int i = 0; i < COUNT; ++i) begin + automatic bit fiftyfifty = i[0]; + randsequence(main) + main: count_1 check count_2; + check: count_3 { if (fiftyfifty) break; } count_4; + count_1: { ++counts[1]; }; + count_2: { ++counts[2]; }; + count_3: { ++counts[3]; }; + count_4: { ++counts[4]; }; + endsequence + end + `checkd(counts[1], COUNT * 1 / 1); + `checkd(counts[2], COUNT * 1 / 2); // break + `checkd(counts[3], COUNT * 1 / 1); + `checkd(counts[4], COUNT * 1 / 2); // break or return + + // return + prep(); + for (int i = 0; i < COUNT; ++i) begin + automatic bit fiftyfifty = i[0]; + randsequence(main) + main: count_1 check count_2; + check: count_3 { if (fiftyfifty) return; } count_4; + count_1: { ++counts[1]; }; + count_2: { ++counts[2]; }; + count_3: { ++counts[3]; }; + count_4: { ++counts[4]; }; + endsequence + end + `checkd(counts[1], COUNT * 1 / 1); + `checkd(counts[2], COUNT * 1 / 1); // return + `checkd(counts[3], COUNT * 1 / 1); + `checkd(counts[4], COUNT * 1 / 2); // break or return + + // functions + prep(); + for (int i = 0; i < COUNT; ++i) begin + randsequence(main) + main: f_1 f_2 f_3; + f_1 : func(10); + f_2 : func(20); + f_3 : fnoarg; + void func(int n) : { counts[1] += n; }; + void fnoarg : { ++counts[2]; }; + endsequence + end + `checkd(counts[1], COUNT * (10 + 20)); + `checkd(counts[2], COUNT * 1 / 1); // return + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_recursive_method.pl b/test_regress/t/t_recursive_method.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_recursive_method.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_recursive_method.v b/test_regress/t/t_recursive_method.v new file mode 100644 index 000000000..d89d27a29 --- /dev/null +++ b/test_regress/t/t_recursive_method.v @@ -0,0 +1,70 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +class Fib; + function int get_fib(int n); + if (n == 0 || n == 1) + return n; + else + return get_fib(n - 1) + get_fib(n - 2); + endfunction +endclass + +class FibStatic; + static function int get_fib(int n); + if (n == 0 || n == 1) + return n; + else + return get_fib(n - 1) + get_fib(n - 2); + endfunction +endclass + +class Factorial; + static function int factorial(int n); + return fact(n, 1); + endfunction + static function int fact(int n, int acc); + if (n < 2) + fact = acc; + else + fact = fact(n - 1, acc * n); + endfunction +endclass + +class Getter3 #(int T=5); + static function int get_3(); + if (T == 3) + return 3; + else + return Getter3#(3)::get_3(); + endfunction +endclass + +module t (/*AUTOARG*/); + + initial begin + Fib fib = new; + Getter3 getter3 = new; + + if (fib.get_fib(0) != 0) $stop; + if (fib.get_fib(1) != 1) $stop; + if (fib.get_fib(8) != 21) $stop; + + if (FibStatic::get_fib(0) != 0) $stop; + if (FibStatic::get_fib(1) != 1) $stop; + if (FibStatic::get_fib(8) != 21) $stop; + + if (Factorial::factorial(0) != 1) $stop; + if (Factorial::factorial(1) != 1) $stop; + if (Factorial::factorial(6) != 720) $stop; + + if (getter3.get_3() != 3) $stop; + if (Getter3#(3)::get_3() != 3) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_reloop_offset.v b/test_regress/t/t_reloop_offset.v old mode 100755 new mode 100644 diff --git a/test_regress/t/t_savable_open_bad2.pl b/test_regress/t/t_savable_open_bad2.pl index f7e08a422..445737f1a 100755 --- a/test_regress/t/t_savable_open_bad2.pl +++ b/test_regress/t/t_savable_open_bad2.pl @@ -16,6 +16,7 @@ compile( ); execute( + check_finished => 0, ); ok(1); diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp index bfd276936..9d1e4a39e 100644 --- a/test_regress/t/t_scope_map.cpp +++ b/test_regress/t/t_scope_map.cpp @@ -20,7 +20,7 @@ const unsigned long long dt_2 = 3; int main(int argc, char** argv) { const std::unique_ptr contextp{new VerilatedContext}; - Vt_scope_map* top = new Vt_scope_map{contextp.get(), "top"}; + VM_PREFIX* top = new VM_PREFIX{contextp.get(), "top"}; contextp->debug(0); contextp->traceEverOn(true); diff --git a/test_regress/t/t_select_bad_msb.out b/test_regress/t/t_select_bad_msb.out index 6c52f62b3..1ec1c350e 100644 --- a/test_regress/t/t_select_bad_msb.out +++ b/test_regress/t/t_select_bad_msb.out @@ -1,4 +1,4 @@ -%Warning-LITENDIAN: t/t_select_bad_msb.v:12:8: Little bit endian vector: left < right of bit range: [0:22] +%Warning-LITENDIAN: t/t_select_bad_msb.v:12:8: Big bit endian vector: left < right of bit range: [0:22] : ... In instance t 12 | reg [0:22] backwd; | ^ diff --git a/test_regress/t/t_select_bad_range4.out b/test_regress/t/t_select_bad_range4.out index edbedb1b0..302b44d6e 100644 --- a/test_regress/t/t_select_bad_range4.out +++ b/test_regress/t/t_select_bad_range4.out @@ -11,11 +11,11 @@ 20 | sel2 = mi[44 +: -1]; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Warning-WIDTH: t/t_select_bad_range4.v:20:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 3 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_select_bad_range4.v:20:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 3 bits. + : ... In instance t 20 | sel2 = mi[44 +: -1]; | ^ - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error: t/t_select_bad_range4.v:21:16: Width of :+ or :- is huge; vector of over 1 billion bits: 32'h20000000 : ... In instance t 21 | sel2 = mi[44 +: 1<<29]; @@ -28,8 +28,8 @@ : ... In instance t 21 | sel2 = mi[44 +: 1<<29]; | ^ -%Warning-WIDTH: t/t_select_bad_range4.v:21:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 20000000 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_select_bad_range4.v:21:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 20000000 bits. + : ... In instance t 21 | sel2 = mi[44 +: 1<<29]; | ^ %Error: t/t_select_bad_range4.v:22:23: Expecting expression to be constant, but variable isn't const: 'nonconst' @@ -40,16 +40,16 @@ : ... In instance t 22 | sel2 = mi[44 +: nonconst]; | ^~~~~~~~ -%Warning-WIDTH: t/t_select_bad_range4.v:22:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_select_bad_range4.v:22:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. + : ... In instance t 22 | sel2 = mi[44 +: nonconst]; | ^ -%Warning-WIDTH: t/t_select_bad_range4.v:23:17: Operator SUB expects 20 or 6 bits on the LHS, but LHS's VARREF 'nonconst' generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_select_bad_range4.v:23:17: Operator SUB expects 20 or 6 bits on the LHS, but LHS's VARREF 'nonconst' generates 1 bits. + : ... In instance t 23 | sel2 = mi[nonconst]; | ^~~~~~~~ -%Warning-WIDTH: t/t_select_bad_range4.v:23:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_select_bad_range4.v:23:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. + : ... In instance t 23 | sel2 = mi[nonconst]; | ^ %Error: t/t_select_bad_range4.v:24:17: Expecting expression to be constant, but variable isn't const: 'nonconst' @@ -68,8 +68,8 @@ : ... In instance t 24 | sel2 = mi[nonconst : nonconst]; | ^~~~~~~~ -%Warning-WIDTH: t/t_select_bad_range4.v:24:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_select_bad_range4.v:24:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 1 bits. + : ... In instance t 24 | sel2 = mi[nonconst : nonconst]; | ^ %Warning-SELRANGE: t/t_select_bad_range4.v:25:16: Extracting 20000001 bits from only 6 bit number @@ -80,8 +80,8 @@ : ... In instance t 25 | sel2 = mi[1<<29 : 0]; | ^ -%Warning-WIDTH: t/t_select_bad_range4.v:25:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 20000001 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_select_bad_range4.v:25:12: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS's SEL generates 20000001 bits. + : ... In instance t 25 | sel2 = mi[1<<29 : 0]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_select_bad_range5.out b/test_regress/t/t_select_bad_range5.out index b97758309..0c84ef079 100644 --- a/test_regress/t/t_select_bad_range5.out +++ b/test_regress/t/t_select_bad_range5.out @@ -12,8 +12,8 @@ : ... In instance t 16 | assign mi = unk[3:2]; | ^ -%Warning-WIDTH: t/t_select_bad_range5.v:16:14: Operator ASSIGNW expects 1 bits on the Assign RHS, but Assign RHS's SEL generates 2 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_select_bad_range5.v:16:14: Operator ASSIGNW expects 1 bits on the Assign RHS, but Assign RHS's SEL generates 2 bits. + : ... In instance t 16 | assign mi = unk[3:2]; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_split_var_1_bad.out b/test_regress/t/t_split_var_1_bad.out index 6249c2943..0b8fbf11a 100644 --- a/test_regress/t/t_split_var_1_bad.out +++ b/test_regress/t/t_split_var_1_bad.out @@ -19,8 +19,8 @@ : ... In instance t.i_sub3 90 | assign outwires[12] = inwires[13]; | ^ -%Warning-WIDTH: t/t_split_var_1_bad.v:41:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's FUNCREF 'bad_func' generates 32 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_split_var_1_bad.v:41:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's FUNCREF 'bad_func' generates 32 bits. + : ... In instance t 41 | i_sub0.cannot_split1[1] = bad_func(addr, rd_data0); | ^ %Error: t/t_split_var_1_bad.v:79:16: Illegal assignment of constant to unpacked array diff --git a/test_regress/t/t_stacktrace.v b/test_regress/t/t_stacktrace.v index c4662bf82..b8ad7e34d 100644 --- a/test_regress/t/t_stacktrace.v +++ b/test_regress/t/t_stacktrace.v @@ -6,7 +6,7 @@ module t; - task t; + task automatic t; // verilator no_inline_task string trace; diff --git a/test_regress/t/t_stmt_incr_unsup.out b/test_regress/t/t_stmt_incr_unsup.out new file mode 100644 index 000000000..9bc34d883 --- /dev/null +++ b/test_regress/t/t_stmt_incr_unsup.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_stmt_incr_unsup.v:17:12: Unsupported: Inc/Dec of expression with side-effects + 17 | arr[postincrement_i()]++; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_stmt_incr_unsup.pl b/test_regress/t/t_stmt_incr_unsup.pl new file mode 100755 index 000000000..35d749208 --- /dev/null +++ b/test_regress/t/t_stmt_incr_unsup.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2009 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_stmt_incr_unsup.v b/test_regress/t/t_stmt_incr_unsup.v new file mode 100644 index 000000000..e1682331a --- /dev/null +++ b/test_regress/t/t_stmt_incr_unsup.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 Krzysztof Boronski. +// SPDX-License-Identifier: CC0-1.0 + +int i = 0; + +function int postincrement_i; + return i++; +endfunction + +module t; + initial begin + int arr [1:0] = {0, 0}; + i = 0; + arr[postincrement_i()]++; + $display("Value: %d", i); + end +endmodule diff --git a/test_regress/t/t_stream_bad.out b/test_regress/t/t_stream_bad.out index d374c004f..970a91901 100644 --- a/test_regress/t/t_stream_bad.out +++ b/test_regress/t/t_stream_bad.out @@ -6,10 +6,10 @@ : ... In instance t 12 | initial packed_data_32 = {<<$random{byte_in}}; | ^~ -%Warning-WIDTH: t/t_stream_bad.v:12:27: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_bad.v:12:27: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. + : ... In instance t 12 | initial packed_data_32 = {<<$random{byte_in}}; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_stream_integer_type.out b/test_regress/t/t_stream_integer_type.out index 96728e3ee..ab803e9a1 100644 --- a/test_regress/t/t_stream_integer_type.out +++ b/test_regress/t/t_stream_integer_type.out @@ -1,147 +1,147 @@ -%Warning-WIDTH: t/t_stream_integer_type.v:118:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:118:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. + : ... In instance t 118 | packed_data_32 = {<<8{byte_in}}; | ^ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. -%Warning-WIDTH: t/t_stream_integer_type.v:119:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits. - : ... In instance t + ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest + ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:119:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits. + : ... In instance t 119 | packed_data_64 = {<<16{shortint_in}}; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:120:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:120:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. + : ... In instance t 120 | packed_data_128 = {<<32{int_in}}; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:121:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:121:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. + : ... In instance t 121 | packed_data_128_i = {<<32{integer_in}}; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:122:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:122:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits. + : ... In instance t 122 | packed_data_256 = {<<64{longint_in}}; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:123:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:123:28: Operator ASSIGN expects 256 bits on the Assign RHS, but Assign RHS's STREAML generates 64 bits. + : ... In instance t 123 | packed_time_256 = {<<64{time_in}}; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:124:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:124:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. + : ... In instance t 124 | v_packed_data_32 = {<<8{bit_in}}; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:125:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:125:28: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's STREAML generates 16 bits. + : ... In instance t 125 | v_packed_data_64 = {<<16{logic_in}}; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:126:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:126:28: Operator ASSIGN expects 128 bits on the Assign RHS, but Assign RHS's STREAML generates 32 bits. + : ... In instance t 126 | v_packed_data_128 = {<<32{reg_in}}; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:128:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_32' generates 32 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:128:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_32' generates 32 bits. + : ... In instance t 128 | {<<8{byte_out}} = packed_data_32; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:129:31: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_64' generates 64 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:129:31: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_64' generates 64 bits. + : ... In instance t 129 | {<<16{shortint_out}} = packed_data_64; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:130:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128' generates 128 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:130:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128' generates 128 bits. + : ... In instance t 130 | {<<32{int_out}} = packed_data_128; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:131:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128_i' generates 128 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:131:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_128_i' generates 128 bits. + : ... In instance t 131 | {<<32{integer_out}} = packed_data_128_i; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:132:31: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_256' generates 256 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:132:31: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_data_256' generates 256 bits. + : ... In instance t 132 | {<<64{longint_out}} = packed_data_256; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:133:31: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_time_256' generates 256 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:133:31: Operator ASSIGN expects 64 bits on the Assign RHS, but Assign RHS's VARREF 'packed_time_256' generates 256 bits. + : ... In instance t 133 | {<<64{time_out}} = packed_time_256; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:134:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_32' generates 32 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:134:31: Operator ASSIGN expects 8 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_32' generates 32 bits. + : ... In instance t 134 | {<<8{bit_out}} = v_packed_data_32; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:135:31: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_64' generates 64 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:135:31: Operator ASSIGN expects 16 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_64' generates 64 bits. + : ... In instance t 135 | {<<16{logic_out}} = v_packed_data_64; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:136:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_128' generates 128 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_stream_integer_type.v:136:31: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's VARREF 'v_packed_data_128' generates 128 bits. + : ... In instance t 136 | {<<32{reg_out}} = v_packed_data_128; | ^ -%Warning-WIDTH: t/t_stream_integer_type.v:150:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. - : ... In instance t +%Warning-WIDTHEXPAND: t/t_stream_integer_type.v:150:28: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's STREAML generates 8 bits. + : ... In instance t 150 | packed_data_32 = {< 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_string_to_bit.v b/test_regress/t/t_string_to_bit.v new file mode 100644 index 000000000..b8b30be23 --- /dev/null +++ b/test_regress/t/t_string_to_bit.v @@ -0,0 +1,106 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got=\"%s\" exp=\"%s\"\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 0; + + string str0; + string str1; + string str2; + + typedef bit [31:0] bit_t; + typedef logic [31:0] logic_t; + typedef bit [55:0] quad_t; + typedef bit [87:0] wide_t; + + bit_t bdata[3]; + bit_t ldata[3]; + quad_t qdata[3]; + wide_t wdata[3]; + + initial begin + str0 = "sm"; + str1 = "medium"; + str2 = "veryverylongwilltruncate"; + bdata[0] = bit_t'(str0); + bdata[1] = bit_t'(str1); + bdata[2] = bit_t'(str2); + `checks(bdata[0], "sm"); + `checks(bdata[1], "dium"); + `checks(bdata[2], "cate"); + if (bdata[0] != 32'h0000736d) $stop; + if (bdata[1] != 32'h6469756d) $stop; + ldata[0] = logic_t'(str0); + ldata[1] = logic_t'(str1); + ldata[2] = logic_t'(str2); + `checks(ldata[0], "sm"); + `checks(ldata[1], "dium"); + `checks(ldata[2], "cate"); + qdata[0] = quad_t'(str0); + qdata[1] = quad_t'(str1); + qdata[2] = quad_t'(str2); + `checks(qdata[0], "sm"); + `checks(qdata[1], "medium"); + `checks(qdata[2], "runcate"); + wdata[0] = wide_t'(str0); + wdata[1] = wide_t'(str1); + wdata[2] = wide_t'(str2); + `checks(wdata[0], "sm"); + `checks(wdata[1], "medium"); + `checks(wdata[2], "illtruncate"); + end + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 1) begin + str0 = "z"; + str1 = "zmedi"; + str2 = "ziggylonglonglongtruncate"; + end + else if (cyc == 2) begin + bdata[0] = bit_t'(str0); + bdata[1] = bit_t'(str1); + bdata[2] = bit_t'(str2); + ldata[0] = logic_t'(str0); + ldata[1] = logic_t'(str1); + ldata[2] = logic_t'(str2); + qdata[0] = quad_t'(str0); + qdata[1] = quad_t'(str1); + qdata[2] = quad_t'(str2); + wdata[0] = wide_t'(str0); + wdata[1] = wide_t'(str1); + wdata[2] = wide_t'(str2); + end + else if (cyc == 3) begin + `checks(bdata[0], "z"); + `checks(bdata[1], "medi"); + `checks(bdata[2], "cate"); + `checks(ldata[0], "z"); + `checks(ldata[1], "medi"); + `checks(ldata[2], "cate"); + `checks(qdata[0], "z"); + `checks(qdata[1], "zmedi"); + `checks(qdata[2], "runcate"); + `checks(wdata[0], "z"); + `checks(wdata[1], "zmedi"); + `checks(wdata[2], "ongtruncate"); + end + // + else if (cyc==99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_struct_contents.pl b/test_regress/t/t_struct_contents.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_struct_contents.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_struct_contents.v b/test_regress/t/t_struct_contents.v new file mode 100644 index 000000000..d4a244994 --- /dev/null +++ b/test_regress/t/t_struct_contents.v @@ -0,0 +1,51 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + typedef enum logic [1:0] { ZERO, ONE } enum_t; + + typedef struct packed { bit a; } struct_packed_t; + typedef union packed { bit a; } union_packed_t; + + //IEEE 1800-2017 7.2.1 + // These are all legal + typedef struct packed { + enum_t e; + shortint si; + int it; + longint li; + byte by; + bit bi; + logic lo; + reg rg; + integer in; + time tim; + struct_packed_t sp; + union_packed_t up; + bit [1:0][2:0] bit_array; + } legal_t; + legal_t legal; + + initial begin + legal.e = ONE; + legal.si = 1; + legal.it = 2; + legal.li = 3; + legal.by = 4; + legal.bi = 1'b1; + legal.lo = 1'b1; + legal.rg = 1'b1; + legal.in = 6; + legal.tim = 7; + legal.sp.a = 1'b1; + legal.up.a = 1'b1; + legal.bit_array[1][1] = 1'b1; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_struct_contents_bad.out b/test_regress/t/t_struct_contents_bad.out new file mode 100644 index 000000000..c39da5643 --- /dev/null +++ b/test_regress/t/t_struct_contents_bad.out @@ -0,0 +1,41 @@ +%Error: t/t_struct_contents_bad.v:20:19: Unpacked data type 'real' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 20 | real r; + | ^ +%Error: t/t_struct_contents_bad.v:22:19: Unpacked data type 'real' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 22 | shortreal sr; + | ^~ +%Error: t/t_struct_contents_bad.v:23:19: Unpacked data type 'real' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 23 | realtime rt; + | ^~ +%Error: t/t_struct_contents_bad.v:24:19: Unpacked data type 'chandle' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 24 | chandle ch; + | ^~ +%Error: t/t_struct_contents_bad.v:25:19: Unpacked data type 'string' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 25 | string s; + | ^ +%Error: t/t_struct_contents_bad.v:26:19: Unpacked data type 'event' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 26 | event e; + | ^ +%Error: t/t_struct_contents_bad.v:27:25: Unpacked data type 'STRUCTDTYPE 't.struct_unpacked_t'' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 27 | struct_unpacked_t sp; + | ^~ +%Error: t/t_struct_contents_bad.v:28:24: Unpacked data type 'UNIONDTYPE 't.union_unpacked_t'' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 28 | union_unpacked_t up; + | ^~ +%Error: t/t_struct_contents_bad.v:29:11: Unpacked data type 'int$[0:1]' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 29 | int uarray[2]; + | ^~~~~~ +%Error: t/t_struct_contents_bad.v:30:11: Unpacked data type 'CLASSREFDTYPE 'Cls'' in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 30 | Cls c; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_struct_contents_bad.pl b/test_regress/t/t_struct_contents_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_struct_contents_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_struct_contents_bad.v b/test_regress/t/t_struct_contents_bad.v new file mode 100644 index 000000000..a6c69763e --- /dev/null +++ b/test_regress/t/t_struct_contents_bad.v @@ -0,0 +1,37 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + typedef enum logic [1:0] { ZERO, ONE } enum_t; + + typedef struct { bit a; } struct_unpacked_t; + typedef union { bit a; } union_unpacked_t; + +class Cls; + bit a; +endclass + + // IEEE 1800-2017 7.2.1 + typedef struct packed { + real r; // BAD + // verilator lint_off SHORTREAL + shortreal sr; // BAD + realtime rt; // BAD + chandle ch; // BAD + string s; // BAD + event e; // BAD + struct_unpacked_t sp; // BAD + union_unpacked_t up; // BAD + int uarray[2]; // BAD + Cls c; // BAd + } illegal_t; + + initial begin + $stop; + end + +endmodule diff --git a/test_regress/t/t_struct_packed_init_bad.out b/test_regress/t/t_struct_packed_init_bad.out new file mode 100644 index 000000000..90d48e049 --- /dev/null +++ b/test_regress/t/t_struct_packed_init_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_struct_packed_init_bad.v:12:17: Initial values not allowed in packed struct/union (IEEE 1800-2017 7.2.1) + : ... In instance t + 12 | bit [3:0] m_lo = P; + | ^~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_struct_packed_init_bad.pl b/test_regress/t/t_struct_packed_init_bad.pl new file mode 100755 index 000000000..35096464e --- /dev/null +++ b/test_regress/t/t_struct_packed_init_bad.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +#execute() + +ok(1); +1; diff --git a/test_regress/t/t_struct_packed_init_bad.v b/test_regress/t/t_struct_packed_init_bad.v new file mode 100644 index 000000000..98d81d2f0 --- /dev/null +++ b/test_regress/t/t_struct_packed_init_bad.v @@ -0,0 +1,21 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + parameter P = 4'h5; + + struct packed { + bit [3:0] m_lo = P; // Bad + bit [3:0] m_hi; + } s; + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_struct_pat.pl b/test_regress/t/t_struct_pat.pl new file mode 100755 index 000000000..1aa73f80a --- /dev/null +++ b/test_regress/t/t_struct_pat.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_struct_pat.v b/test_regress/t/t_struct_pat.v new file mode 100644 index 000000000..931113fc0 --- /dev/null +++ b/test_regress/t/t_struct_pat.v @@ -0,0 +1,103 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + typedef struct { + int a; + int b; + byte c; + } sabcu_t; + + typedef struct packed { + int a; + int b; + byte c; + } sabcp_t; + + sabcu_t abcu; + sabcp_t abcp; + + typedef struct { + int a; + int b4[4]; + } sab4u_t; + + typedef struct packed { + int a; + bit [3:0][31:0] b4; + } sab4p_t; + + sab4u_t ab4u[2][3]; + sab4p_t ab4p[2][3]; + + initial begin + abcp = '{1, 2, 3}; + abcu = '{1, 2, 3}; + if (abcp.a !== 1) $stop; + if (abcp.b !== 2) $stop; + if (abcp.c !== 3) $stop; + if (abcu.a !== 1) $stop; + if (abcu.b !== 2) $stop; + if (abcu.c !== 3) $stop; + + abcp = '{3{40}}; + abcu = '{3{40}}; + if (abcp.a !== 40) $stop; + if (abcp.b !== 40) $stop; + if (abcp.c !== 40) $stop; + if (abcu.a !== 40) $stop; + if (abcu.b !== 40) $stop; + if (abcu.c !== 40) $stop; + + abcp = '{default:4, int:5}; + abcu = '{default:4, int:5}; + if (abcp.a !== 5) $stop; + if (abcp.b !== 5) $stop; + if (abcp.c !== 4) $stop; + if (abcu.a !== 5) $stop; + if (abcu.b !== 5) $stop; + if (abcu.c !== 4) $stop; + + abcp = '{int:6, byte:7, int:8}; + abcu = '{int:6, byte:7, int:8}; + if (abcp.a !== 8) $stop; + if (abcp.b !== 8) $stop; + if (abcp.c !== 7) $stop; + if (abcu.a !== 8) $stop; + if (abcu.b !== 8) $stop; + if (abcu.c !== 7) $stop; + + ab4p = '{2{'{3{'{10, '{2{20, 30}}}}}}}; + ab4u = '{2{'{3{'{10, '{2{20, 30}}}}}}}; + $display("%p", ab4p); + if (ab4p[0][0].a !== 10) $stop; + if (ab4p[0][0].b4[0] !== 30) $stop; + if (ab4p[0][0].b4[1] !== 20) $stop; + if (ab4p[0][0].b4[2] !== 30) $stop; + if (ab4p[0][0].b4[3] !== 20) $stop; + if (ab4p[1][2].a !== 10) $stop; + if (ab4p[1][2].b4[0] !== 30) $stop; + if (ab4p[1][2].b4[1] !== 20) $stop; + if (ab4p[1][2].b4[2] !== 30) $stop; + if (ab4p[1][2].b4[3] !== 20) $stop; + $display("%p", ab4u); + if (ab4u[0][0].a !== 10) $stop; + if (ab4u[0][0].b4[0] !== 20) $stop; + if (ab4u[0][0].b4[1] !== 30) $stop; + if (ab4u[0][0].b4[2] !== 20) $stop; + if (ab4u[0][0].b4[3] !== 30) $stop; + if (ab4u[1][2].a !== 10) $stop; + if (ab4u[1][2].b4[0] !== 20) $stop; + if (ab4u[1][2].b4[1] !== 30) $stop; + if (ab4u[1][2].b4[2] !== 20) $stop; + if (ab4u[1][2].b4[3] !== 30) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_struct_unpacked.v b/test_regress/t/t_struct_unpacked.v index 29a1e69b9..14190f693 100644 --- a/test_regress/t/t_struct_unpacked.v +++ b/test_regress/t/t_struct_unpacked.v @@ -1,9 +1,12 @@ // DESCRIPTION: Verilator: Verilog Test module // // This file ONLY is placed under the Creative Commons Public Domain, for -// any use, without warranty, 2009 by Wilson Snyder. +// any use, without warranty, 2009-2023 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`define stop $stop +`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + module x; typedef struct { int a, b; @@ -15,14 +18,31 @@ module x; embedded_t tab [3:0]; } notembedded_t; + typedef struct { + logic [15:0] m_i; + string m_s; + } istr_t; + notembedded_t p; embedded_t t [1:0]; + istr_t istr; + string s; initial begin t[1].a = 2; p.b.a = 1; if (t[1].a != 2) $stop; if (p.b.a != 1) $stop; + + istr.m_i = 12; + istr.m_s = "str1"; + s = $sformatf("%p", istr); + `checks(s, "'{m_i:'hc, m_s:\"str1\"}"); + + istr = '{m_i: '1, m_s: "str2"}; + s = $sformatf("%p", istr); + `checks(s, "'{m_i:'hffff, m_s:\"str2\"}"); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_struct_unpacked_init.out b/test_regress/t/t_struct_unpacked_init.out new file mode 100644 index 000000000..9e3d7bc11 --- /dev/null +++ b/test_regress/t/t_struct_unpacked_init.out @@ -0,0 +1,6 @@ +%Error-UNSUPPORTED: t/t_struct_unpacked_init.v:12:24: Unsupported: Initial values in struct/union members + : ... In instance t + 12 | bit [3:0] m_lo = P; + | ^ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_struct_unpacked_init.pl b/test_regress/t/t_struct_unpacked_init.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_struct_unpacked_init.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_struct_unpacked_init.v b/test_regress/t/t_struct_unpacked_init.v new file mode 100644 index 000000000..5518ab9e3 --- /dev/null +++ b/test_regress/t/t_struct_unpacked_init.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + parameter P = 4'h5; + + struct { // Can't legally be packed + bit [3:0] m_lo = P; + bit [3:0] m_hi; + } s; + + initial begin + s.m_hi = 4'ha; + if (s.m_lo != 4'h5) $stop; + if (s.m_hi != 4'ha) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_sys_file_basic.v b/test_regress/t/t_sys_file_basic.v index fd64c07a8..35a0d54a8 100644 --- a/test_regress/t/t_sys_file_basic.v +++ b/test_regress/t/t_sys_file_basic.v @@ -24,6 +24,7 @@ module t; reg [16*8:1] letterz; real r; string s; + reg [16*8:1] si; integer i; reg [7:0] v_a,v_b,v_c,v_d; @@ -88,6 +89,9 @@ module t; i = $ferror(file, s); `checkh(i, 2); `checks(s, "No such file or directory"); + si = "xx"; + i = $ferror(file, si); + `checkh(i, 2); end begin diff --git a/test_regress/t/t_sys_file_basic_mcd.out b/test_regress/t/t_sys_file_basic_mcd.out index 636fdaca3..61d320dd4 100644 --- a/test_regress/t/t_sys_file_basic_mcd.out +++ b/test_regress/t/t_sys_file_basic_mcd.out @@ -1,3 +1,4 @@ Sean Connery was the best Bond. To file and to stdout *-* All Finished *-* + diff --git a/test_regress/t/t_sys_file_basic_mcd.v b/test_regress/t/t_sys_file_basic_mcd.v index 54d0aba21..e8329e20d 100644 --- a/test_regress/t/t_sys_file_basic_mcd.v +++ b/test_regress/t/t_sys_file_basic_mcd.v @@ -4,16 +4,17 @@ // any use, without warranty, 2020 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 +`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); module t; `define STR(__s) `"__s`" - task automatic fail(string s); begin + task automatic fail(string s); $display({"FAIL! Reason: ", s}); $stop; - end endtask + endtask - task automatic test1; begin + task automatic test1; int fd[30], fd_fail, fd_success, fd_close, tmp; for (int i = 0; i < 30; i++) begin // Attempt to allocate 30 MCD descriptors; returned descriptors @@ -45,9 +46,9 @@ module t; fd_close = fd[i]; $fclose(fd_close); end - end endtask + endtask - task automatic test2; begin + task automatic test2; // Validate basic MCD functionality. integer fd[3], fd_all, tmp; @@ -65,14 +66,29 @@ module t; $fwrite(fd_all, "All other countries are inferior.\n"); $fwrite(fd_all, "Woe betide those to stand against the mighty Scottish nation.\n"); $fclose(fd_all); - end endtask + endtask - task automatic test3; begin + task automatic test3; + int result; // Write some things to standard output. $fwrite(32'h8000_0001, "Sean Connery was the best Bond.\n"); - end endtask + $fwrite(32'h8000_0001); + $fstrobe(32'h8000_0001); - task automatic test4; begin + result = $fseek(32'hffffffff, 0, 0); + `checkd(result, -1); + + result = $ftell(32'hffffffff); + `checkd(result, -1); + + result = $rewind(32'hffffffff); + `checkd(result, -1); + + result = $feof(0); + `checkd(result, 1); + endtask + + task automatic test4; int fd; // Wide filename fd = $fopen({`STR(`TEST_OBJ_DIR), @@ -80,16 +96,16 @@ module t; "except_to_purposefully_break_my_beautiful_code.dat"}); if (fd == 0) fail("Long filename could not be opened."); $fclose(fd); - end endtask + endtask - task automatic test5; begin + task automatic test5; int fd_all; fd_all = $fopen({`STR(`TEST_OBJ_DIR), "/t_sys_file_basic_mcd_test5.dat"}); if (fd_all == 0) fail("could not be opened."); fd_all |= 1; $fdisplay(fd_all, "To file and to stdout"); $fclose(fd_all); - end endtask + endtask initial begin diff --git a/test_regress/t/t_sys_rand_concat.pl b/test_regress/t/t_sys_rand_concat.pl index 7eb1032d5..9c5d99e16 100755 --- a/test_regress/t/t_sys_rand_concat.pl +++ b/test_regress/t/t_sys_rand_concat.pl @@ -17,7 +17,7 @@ execute( check_finished => 1, ); -for my $file (glob_all("$Self->{obj_dir}/$Self->{VM_PREFIX}___024root__DepSet*__Slow.cpp")) { +for my $file (glob_all("$Self->{obj_dir}/$Self->{vm_prefix}___024root__DepSet*__Slow.cpp")) { file_grep_not($file, qr/(<<|>>)/x); } diff --git a/test_regress/t/t_tagged.out b/test_regress/t/t_tagged.out new file mode 100644 index 000000000..b0279d98d --- /dev/null +++ b/test_regress/t/t_tagged.out @@ -0,0 +1,68 @@ +%Error-UNSUPPORTED: t/t_tagged.v:9:18: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 9 | typedef union tagged { + | ^~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error-UNSUPPORTED: t/t_tagged.v:10:6: Unsupported: void (for tagged unions) + 10 | void m_invalid; + | ^~~~ +%Error-UNSUPPORTED: t/t_tagged.v:18:11: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 18 | u = tagged m_invalid; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:21:16: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' + 21 | case (u) matches + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:22:9: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 22 | tagged m_invalid: ; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:23:9: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 23 | tagged m_int: $stop; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:26:13: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' + 26 | if (u matches tagged m_invalid) ; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:26:21: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 26 | if (u matches tagged m_invalid) ; + | ^~~~~~ +%Error: t/t_tagged.v:26:28: syntax error, unexpected IDENTIFIER + 26 | if (u matches tagged m_invalid) ; + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:27:13: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' + 27 | if (u matches tagged m_int .n) $stop; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:27:21: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 27 | if (u matches tagged m_int .n) $stop; + | ^~~~~~ +%Error: t/t_tagged.v:27:28: syntax error, unexpected IDENTIFIER + 27 | if (u matches tagged m_int .n) $stop; + | ^~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:29:11: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 29 | u = tagged m_int (123); + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:32:16: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' + 32 | case (u) matches + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:33:9: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 33 | tagged m_invalid: $stop; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:34:9: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 34 | tagged m_int .n: if (n !== 123) $stop; + | ^~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:37:13: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' + 37 | if (u matches tagged m_invalid) $stop; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:37:21: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 37 | if (u matches tagged m_invalid) $stop; + | ^~~~~~ +%Error: t/t_tagged.v:37:28: syntax error, unexpected IDENTIFIER + 37 | if (u matches tagged m_invalid) $stop; + | ^~~~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:38:13: Unsupported: SystemVerilog 2005 reserved word not implemented: 'matches' + 38 | if (u matches tagged m_int .n) if (n != 123) $stop; + | ^~~~~~~ +%Error-UNSUPPORTED: t/t_tagged.v:38:21: Unsupported: SystemVerilog 2005 reserved word not implemented: 'tagged' + 38 | if (u matches tagged m_int .n) if (n != 123) $stop; + | ^~~~~~ +%Error: t/t_tagged.v:38:28: syntax error, unexpected IDENTIFIER + 38 | if (u matches tagged m_int .n) if (n != 123) $stop; + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_tagged.pl b/test_regress/t/t_tagged.pl new file mode 100755 index 000000000..877e6133a --- /dev/null +++ b/test_regress/t/t_tagged.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_tagged.v b/test_regress/t/t_tagged.v new file mode 100644 index 000000000..76bd224cd --- /dev/null +++ b/test_regress/t/t_tagged.v @@ -0,0 +1,44 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + typedef union tagged { + void m_invalid; + int m_int; + } u_t; + + u_t u; + string s; + + initial begin + u = tagged m_invalid; + s = $sformatf("%p", u); + $display("%s e.g. '{tagged m_invalid:void}", s); + case (u) matches + tagged m_invalid: ; + tagged m_int: $stop; + default: $stop; + endcase + if (u matches tagged m_invalid) ; + if (u matches tagged m_int .n) $stop; + + u = tagged m_int (123); + s = $sformatf("%p", u); + $display("'%s e.g. '{tagged m_int:123}", s); + case (u) matches + tagged m_invalid: $stop; + tagged m_int .n: if (n !== 123) $stop; + default: $stop; + endcase + if (u matches tagged m_invalid) $stop; + if (u matches tagged m_int .n) if (n != 123) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_timing_debug1.out b/test_regress/t/t_timing_debug1.out index 5775d0dde..3a8e37eeb 100644 --- a/test_regress/t/t_timing_debug1.out +++ b/test_regress/t/t_timing_debug1.out @@ -11,7 +11,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___eval_initial__TOP__1 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:17 -V{t#,#}+ Vt_timing_debug1___024root___eval_initial__TOP__2 --V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_initial__TOP__3 -V{t#,#}+ Vt_timing_debug1___024root___eval_settle -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__stl @@ -45,7 +45,7 @@ -V{t#,#} - Process waiting at t/t_timing_sched.v:18 -V{t#,#} - Process waiting at t/t_timing_sched.v:17 -V{t#,#} Committing processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 @@ -74,7 +74,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 3: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 3: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 3: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 @@ -134,7 +134,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 6: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 6: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 @@ -173,7 +173,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 7: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 9: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 @@ -207,7 +207,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 9: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 9: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 @@ -259,7 +259,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 11: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:10 @@ -283,11 +283,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Ready processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#} Ready processes waiting for @(posedge t.clk2): -V{t#,#} - Process waiting at t/t_timing_sched.v:18 -V{t#,#} Resuming processes waiting for @(posedge t.clk2) --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -324,15 +324,15 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 12: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -340,7 +340,7 @@ -V{t#,#} 'act' region trigger index 0 is active: @([hybrid] __VassignWtmp_t.clk1__0) -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#} Committing processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 @@ -367,7 +367,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 13: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 15: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 @@ -400,7 +400,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 15: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 15: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes @@ -457,7 +457,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 18: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 18: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -495,7 +495,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 19: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 21: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 @@ -528,7 +528,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 21: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 21: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes @@ -579,7 +579,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 22: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 24: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -617,7 +617,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 24: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 24: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:13 @@ -655,7 +655,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 25: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 27: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 @@ -688,7 +688,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 27: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 27: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes @@ -739,7 +739,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 30: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 30: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -777,7 +777,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 31: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 @@ -810,7 +810,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 33: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes @@ -840,11 +840,11 @@ -V{t#,#} Resuming processes waiting for @(posedge t.clk1) -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:17 -V{t#,#} Ready processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#} Ready processes waiting for @(posedge t.clk2): -V{t#,#} - Process waiting at t/t_timing_sched.v:18 -V{t#,#} Resuming processes waiting for @(posedge t.clk2) --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -883,14 +883,14 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 34: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 34: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 36: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 --V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 --V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -898,7 +898,7 @@ -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#} Committing processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_nba -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -917,7 +917,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 36: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 36: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -955,7 +955,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 37: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 39: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 @@ -988,7 +988,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 39: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 39: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes @@ -1045,7 +1045,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 42: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 42: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -1083,7 +1083,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 43: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 @@ -1116,7 +1116,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 44: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes @@ -1153,7 +1153,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 45: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes @@ -1204,7 +1204,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 48: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 48: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -1242,7 +1242,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 49: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 51: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 @@ -1275,7 +1275,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 51: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 51: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes @@ -1326,7 +1326,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 54: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 54: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -1364,7 +1364,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 55: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:10 @@ -1390,11 +1390,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Ready processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#} Ready processes waiting for @(posedge t.clk2): -V{t#,#} - Process waiting at t/t_timing_sched.v:18 -V{t#,#} Resuming processes waiting for @(posedge t.clk2) --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -1431,13 +1431,13 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 56: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 56: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 --V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1445,7 +1445,7 @@ -V{t#,#} No triggers active -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#} Committing processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_nba -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1464,7 +1464,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 57: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:13 -V{t#,#} Resuming delayed processes @@ -1521,7 +1521,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 60: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 60: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -1559,7 +1559,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 61: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 63: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 @@ -1592,7 +1592,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 63: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 63: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes @@ -1643,7 +1643,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 66: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -1685,7 +1685,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 67: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 69: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:13 @@ -1718,7 +1718,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 69: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 69: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes @@ -1769,7 +1769,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 72: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 72: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:17 @@ -1807,7 +1807,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 73: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 75: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 @@ -1840,7 +1840,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 75: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 75: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Resuming delayed processes @@ -1891,7 +1891,7 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 77: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 79: Process waiting at t/t_timing_sched.v:17 @@ -1913,11 +1913,11 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Ready processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#} Ready processes waiting for @(posedge t.clk2): -V{t#,#} - Process waiting at t/t_timing_sched.v:18 -V{t#,#} Resuming processes waiting for @(posedge t.clk2) --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:18 -V{t#,#} Suspending process waiting for @(posedge t.clk1) at t/t_timing_sched.v:18 -V{t#,#}+ Vt_timing_debug1___024root___eval_act @@ -1954,17 +1954,17 @@ -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#} Delayed processes: --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:48 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:52 -V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 79: Process waiting at t/t_timing_sched.v:10 -V{t#,#} Awaiting time 88: Process waiting at t/t_timing_sched.v:13 --V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Awaiting time 78: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming delayed processes --V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:46 +-V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:50 -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:13 *-* All Finished *-* -V{t#,#} Resuming: Process waiting at t/t_timing_sched.v:10 --V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:46 +-V{t#,#} Suspending process waiting for @(posedge t.clk2) at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_comb__TOP__0 -V{t#,#}+ Vt_timing_debug1___024root___eval_triggers__act @@ -1972,7 +1972,7 @@ -V{t#,#} 'act' region trigger index 0 is active: @([hybrid] __VassignWtmp_t.clk1__0) -V{t#,#}+ Vt_timing_debug1___024root___timing_commit -V{t#,#} Committing processes waiting for @(posedge t.clk2): --V{t#,#} - Process waiting at t/t_timing_sched.v:46 +-V{t#,#} - Process waiting at t/t_timing_sched.v:50 -V{t#,#}+ Vt_timing_debug1___024root___timing_resume -V{t#,#}+ Vt_timing_debug1___024root___eval_act -V{t#,#}+ Vt_timing_debug1___024root___act_sequent__TOP__0 diff --git a/test_regress/t/t_timing_sched.v b/test_regress/t/t_timing_sched.v index 57fa10fcd..6bb015fb9 100644 --- a/test_regress/t/t_timing_sched.v +++ b/test_regress/t/t_timing_sched.v @@ -19,7 +19,9 @@ module t; int a2 = 0; always_comb begin + // verilator lint_off MULTIDRIVEN a2 = a1 << 1; + // verilator lint_on MULTIDRIVEN `ifdef TEST_VERBOSE $display("[%0t] a2 = %0d", $time, a2); `endif @@ -27,7 +29,9 @@ module t; int b2 = 0; always_comb begin + // verilator lint_off MULTIDRIVEN b2 = b1 << 2; + // verilator lint_on MULTIDRIVEN `ifdef TEST_VERBOSE $display("[%0t] b2 = %0d", $time, b2); `endif diff --git a/test_regress/t/t_timing_sched_if.v b/test_regress/t/t_timing_sched_if.v index faa84e266..768c7a82c 100644 --- a/test_regress/t/t_timing_sched_if.v +++ b/test_regress/t/t_timing_sched_if.v @@ -25,7 +25,9 @@ module t; int a2 = 0; always_comb begin + // verilator lint_off MULTIDRIVEN a2 = a1 << 1; + // verilator lint_on MULTIDRIVEN `ifdef TEST_VERBOSE $display("[%0t] a2 = %0d", $time, a2); `endif @@ -33,7 +35,9 @@ module t; int b2 = 0; always_comb begin + // verilator lint_off MULTIDRIVEN b2 = b1 << 2; + // verilator lint_on MULTIDRIVEN `ifdef TEST_VERBOSE $display("[%0t] b2 = %0d", $time, b2); `endif @@ -41,7 +45,9 @@ module t; int c2 = 0; always_comb begin + // verilator lint_off MULTIDRIVEN c2 = c1 << 3; + // verilator lint_on MULTIDRIVEN `ifdef TEST_VERBOSE $display("[%0t] c2 = %0d", $time, c2); `endif diff --git a/test_regress/t/t_timing_sched_nba.v b/test_regress/t/t_timing_sched_nba.v index 4106d755c..d09a4778a 100644 --- a/test_regress/t/t_timing_sched_nba.v +++ b/test_regress/t/t_timing_sched_nba.v @@ -19,7 +19,9 @@ module t; int a2 = 0; always_comb begin + // verilator lint_off MULTIDRIVEN a2 = a1 << 1; + // verilator lint_on MULTIDRIVEN `ifdef TEST_VERBOSE $display("[%0t] a2 = %0d", $time, a2); `endif @@ -27,7 +29,9 @@ module t; int b2 = 0; always_comb begin + // verilator lint_off MULTIDRIVEN b2 = b1 << 2; + // verilator lint_on MULTIDRIVEN `ifdef TEST_VERBOSE $display("[%0t] b2 = %0d", $time, b2); `endif diff --git a/test_regress/t/t_timing_wait_long.out b/test_regress/t/t_timing_wait_long.out new file mode 100644 index 000000000..a75a6bc67 --- /dev/null +++ b/test_regress/t/t_timing_wait_long.out @@ -0,0 +1,10 @@ +Current realtime: 5000000 == 5000000000 +Current realtime: 10000001 == 10000001 +Current realtime: 15000000 == 15000000 +FULL_TIME: 5000000.000000 +Current realtime: 20000000 == 20000000 +FIT_TIME: 5000000 -- 5000000.000000 +Current realtime: 25000000 == 25000000 +TRUNCATED_TIME: 805696 -- 805696.000000 +Current realtime: 25805696 == 25805696 +*-* All Finished *-* diff --git a/test_regress/t/t_timing_wait_long.pl b/test_regress/t/t_timing_wait_long.pl new file mode 100755 index 000000000..549b8ba35 --- /dev/null +++ b/test_regress/t/t_timing_wait_long.pl @@ -0,0 +1,28 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if (!$Self->have_coroutines) { + skip("No coroutine support"); +} +else { + compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + + execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); +} +ok(1); +1; diff --git a/test_regress/t/t_timing_wait_long.v b/test_regress/t/t_timing_wait_long.v new file mode 100644 index 000000000..c9417b913 --- /dev/null +++ b/test_regress/t/t_timing_wait_long.v @@ -0,0 +1,46 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +`timescale 1ns/1ps + +module timing_wait_long(); + localparam real FULL_TIME = 5e6; + /* verilator lint_off WIDTHTRUNC */ + localparam [22:0] FIT_TIME = int'(5e6); + localparam [21:0] TRUNCATED_TIME = int'(5e6); // 805696 + /* verilator lint_on WIDTHTRUNC */ + + real realvar_time = 5e6; + time timevar; + initial begin + #5ms; + $display("Current realtime: %d == %d", time'($realtime), time'(1 * 5e9)); + + realvar_time = realvar_time + 1; + #realvar_time; + $display("Current realtime: %d == %d", time'($realtime), time'(2 * 5e6 + 1)); + + timevar = time'(realvar_time - 2); + #timevar; + $display("Current realtime: %d == %d", time'($realtime), time'(3 * 5e6)); + + $display("FULL_TIME: %f", FULL_TIME); + #FULL_TIME; + $display("Current realtime: %d == %d", time'($realtime), time'(4 * 5e6)); + + $display("FIT_TIME: %d -- %f", FIT_TIME, real'(FIT_TIME)); + #FIT_TIME; + $display("Current realtime: %d == %d", time'($realtime), time'(5 * 5e6)); + + $display("TRUNCATED_TIME: %d -- %f", TRUNCATED_TIME, real'(TRUNCATED_TIME)); + #TRUNCATED_TIME; + $display("Current realtime: %d == %d", time'($realtime), time'(5 * 5e6 + real'(int'(5e6) % 2**22))); + + $write("*-* All Finished *-*\n"); + $finish(); + end + +endmodule diff --git a/test_regress/t/t_trace_cat.cpp b/test_regress/t/t_trace_cat.cpp index 488eb4187..1dc631d14 100644 --- a/test_regress/t/t_trace_cat.cpp +++ b/test_regress/t/t_trace_cat.cpp @@ -27,7 +27,7 @@ int main(int argc, char** argv) { Verilated::traceEverOn(true); Verilated::commandArgs(argc, argv); - std::unique_ptr top{new VM_PREFIX("top")}; + std::unique_ptr top{new VM_PREFIX{"top"}}; std::unique_ptr tfp{new VerilatedVcdC}; top->trace(tfp.get(), 99); diff --git a/test_regress/t/t_trace_cat_fst.cpp b/test_regress/t/t_trace_cat_fst.cpp index af8e3cdf3..2467ebc39 100644 --- a/test_regress/t/t_trace_cat_fst.cpp +++ b/test_regress/t/t_trace_cat_fst.cpp @@ -27,7 +27,7 @@ int main(int argc, char** argv) { Verilated::traceEverOn(true); Verilated::commandArgs(argc, argv); - std::unique_ptr top{new VM_PREFIX("top")}; + std::unique_ptr top{new VM_PREFIX{"top"}}; std::unique_ptr tfp{new VerilatedFstC}; top->trace(tfp.get(), 99); diff --git a/test_regress/t/t_trace_decoration.pl b/test_regress/t/t_trace_decoration.pl index fd2355ca5..e717c3d12 100755 --- a/test_regress/t/t_trace_decoration.pl +++ b/test_regress/t/t_trace_decoration.pl @@ -18,7 +18,7 @@ execute( check_finished => 1, ); -file_grep_not("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr!// Body!x); +file_grep_not("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr!// Body!x); ok(1); 1; diff --git a/test_regress/t/t_trace_dumpvars_dyn.cpp b/test_regress/t/t_trace_dumpvars_dyn.cpp index f143e04ba..57df372be 100644 --- a/test_regress/t/t_trace_dumpvars_dyn.cpp +++ b/test_regress/t/t_trace_dumpvars_dyn.cpp @@ -24,7 +24,7 @@ int main(int argc, char** argv) { Verilated::traceEverOn(true); Verilated::commandArgs(argc, argv); - std::unique_ptr top{new VM_PREFIX("top")}; + std::unique_ptr top{new VM_PREFIX{"top"}}; #if defined(T_TRACE_DUMPVARS_DYN_VCD_0) || defined(T_TRACE_DUMPVARS_DYN_VCD_1) std::unique_ptr tfp{new VerilatedVcdC}; diff --git a/test_regress/t/t_trace_public_func.cpp b/test_regress/t/t_trace_public_func.cpp index 6cd30c21f..a05820e24 100644 --- a/test_regress/t/t_trace_public_func.cpp +++ b/test_regress/t/t_trace_public_func.cpp @@ -32,7 +32,7 @@ int main(int argc, char** argv) { Verilated::traceEverOn(true); Verilated::commandArgs(argc, argv); - std::unique_ptr top{new VM_PREFIX("top")}; + std::unique_ptr top{new VM_PREFIX{"top"}}; std::unique_ptr tfp{new VerilatedVcdC}; top->trace(tfp.get(), 99); diff --git a/test_regress/t/t_trace_public_sig_vlt.pl b/test_regress/t/t_trace_public_sig_vlt.pl index 2bf507248..60fef27d0 100755 --- a/test_regress/t/t_trace_public_sig_vlt.pl +++ b/test_regress/t/t_trace_public_sig_vlt.pl @@ -22,7 +22,7 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_trace_rollover.cpp b/test_regress/t/t_trace_rollover.cpp index b07466a29..ce4b6e130 100644 --- a/test_regress/t/t_trace_rollover.cpp +++ b/test_regress/t/t_trace_rollover.cpp @@ -21,7 +21,7 @@ int main(int argc, char** argv) { Verilated::traceEverOn(true); Verilated::commandArgs(argc, argv); - std::unique_ptr top{new VM_PREFIX("top")}; + std::unique_ptr top{new VM_PREFIX{"top"}}; std::unique_ptr tfp{new VerilatedVcdC}; top->trace(tfp.get(), 99); diff --git a/test_regress/t/t_trace_split_cfuncs.v b/test_regress/t/t_trace_split_cfuncs.v index cf364ad5a..c2750d468 100644 --- a/test_regress/t/t_trace_split_cfuncs.v +++ b/test_regress/t/t_trace_split_cfuncs.v @@ -6,9 +6,9 @@ module t (); - initial begin - $dumpfile("dump.vcd"); - $dumpvars(); - end + initial begin + $dumpfile("dump.vcd"); + $dumpvars(); + end endmodule diff --git a/test_regress/t/t_trace_split_cfuncs_dpi_export.v b/test_regress/t/t_trace_split_cfuncs_dpi_export.v index cec80cc3c..aa82f7813 100644 --- a/test_regress/t/t_trace_split_cfuncs_dpi_export.v +++ b/test_regress/t/t_trace_split_cfuncs_dpi_export.v @@ -6,13 +6,13 @@ module t (); - function automatic void func(); - endfunction - export "DPI-C" function func; + function automatic void func(); + endfunction + export "DPI-C" function func; - initial begin - $dumpfile("dump.vcd"); - $dumpvars(); - end + initial begin + $dumpfile("dump.vcd"); + $dumpvars(); + end endmodule diff --git a/test_regress/t/t_trace_two_dump_cc.pl b/test_regress/t/t_trace_two_dump_cc.pl index d4643e039..b12ff1c88 100755 --- a/test_regress/t/t_trace_two_dump_cc.pl +++ b/test_regress/t/t_trace_two_dump_cc.pl @@ -17,7 +17,7 @@ compile( make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['-trace'], ); diff --git a/test_regress/t/t_trace_two_dump_sc.pl b/test_regress/t/t_trace_two_dump_sc.pl index dd789a58b..68e985871 100755 --- a/test_regress/t/t_trace_two_dump_sc.pl +++ b/test_regress/t/t_trace_two_dump_sc.pl @@ -20,7 +20,7 @@ else { make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['-sc -trace'], ); diff --git a/test_regress/t/t_trace_two_dumpfst_cc.out b/test_regress/t/t_trace_two_dumpfst_cc.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_trace_two_dumpfst_cc.pl b/test_regress/t/t_trace_two_dumpfst_cc.pl index 4c1b2c968..e672f49c0 100755 --- a/test_regress/t/t_trace_two_dumpfst_cc.pl +++ b/test_regress/t/t_trace_two_dumpfst_cc.pl @@ -17,7 +17,7 @@ compile( make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['--trace-fst --trace-threads 1 -DTEST_FST'], ); diff --git a/test_regress/t/t_trace_two_hdr_cc.pl b/test_regress/t/t_trace_two_hdr_cc.pl index f0c386bbb..665808c3b 100755 --- a/test_regress/t/t_trace_two_hdr_cc.pl +++ b/test_regress/t/t_trace_two_hdr_cc.pl @@ -17,7 +17,7 @@ compile( make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['-trace'], ); diff --git a/test_regress/t/t_trace_two_hdr_sc.pl b/test_regress/t/t_trace_two_hdr_sc.pl index 8374fcfee..89776af8b 100755 --- a/test_regress/t/t_trace_two_hdr_sc.pl +++ b/test_regress/t/t_trace_two_hdr_sc.pl @@ -20,7 +20,7 @@ else { make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['-sc -trace'], ); diff --git a/test_regress/t/t_trace_two_hdrfst_cc.out b/test_regress/t/t_trace_two_hdrfst_cc.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_trace_two_hdrfst_cc.pl b/test_regress/t/t_trace_two_hdrfst_cc.pl index af0d8307f..e6b4a6008 100755 --- a/test_regress/t/t_trace_two_hdrfst_cc.pl +++ b/test_regress/t/t_trace_two_hdrfst_cc.pl @@ -17,7 +17,7 @@ compile( make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['--trace-fst --trace-threads 1'], ); diff --git a/test_regress/t/t_trace_two_port_cc.pl b/test_regress/t/t_trace_two_port_cc.pl index 7e348f19b..1bc4268b2 100755 --- a/test_regress/t/t_trace_two_port_cc.pl +++ b/test_regress/t/t_trace_two_port_cc.pl @@ -17,7 +17,7 @@ compile( make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['-trace'], ); diff --git a/test_regress/t/t_trace_two_port_sc.pl b/test_regress/t/t_trace_two_port_sc.pl index e62e64a3b..1bc1d29af 100755 --- a/test_regress/t/t_trace_two_port_sc.pl +++ b/test_regress/t/t_trace_two_port_sc.pl @@ -20,7 +20,7 @@ else { make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['-sc -trace'], ); diff --git a/test_regress/t/t_trace_two_portfst_cc.out b/test_regress/t/t_trace_two_portfst_cc.out old mode 100755 new mode 100644 diff --git a/test_regress/t/t_trace_two_portfst_cc.pl b/test_regress/t/t_trace_two_portfst_cc.pl index 676bfb508..f9782d372 100755 --- a/test_regress/t/t_trace_two_portfst_cc.pl +++ b/test_regress/t/t_trace_two_portfst_cc.pl @@ -17,7 +17,7 @@ compile( make_main => 0, verilator_make_gmake => 0, top_filename => 't_trace_two_b.v', - VM_PREFIX => 'Vt_trace_two_b', + vm_prefix => 'Vt_trace_two_b', verilator_flags2 => ['--trace-fst --trace-threads 1'], ); diff --git a/test_regress/t/t_tri_and_eqcase.out b/test_regress/t/t_tri_and_eqcase.out index 315a41e1f..d319b4996 100644 --- a/test_regress/t/t_tri_and_eqcase.out +++ b/test_regress/t/t_tri_and_eqcase.out @@ -1,8 +1,8 @@ -%Error-UNSUPPORTED: t/t_tri_and_eqcase.v:9:28: Unsupported tristate construct: AND in function getEnExprBasedOnOriginalp - 9 | logic b = 1'z === (clk1 & clk2); - | ^ +%Error-UNSUPPORTED: t/t_tri_and_eqcase.v:9:29: Unsupported tristate construct: AND in function getEnExprBasedOnOriginalp + 9 | logic b = 1'bz === (clk1 & clk2); + | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Internal Error: t/t_tri_and_eqcase.v:9:18: ../V3Ast.cpp:#: Null item passed to setOp2p - 9 | logic b = 1'z === (clk1 & clk2); - | ^~~ +%Error: Internal Error: t/t_tri_and_eqcase.v:9:19: ../V3Ast.cpp:#: Null item passed to setOp2p + 9 | logic b = 1'bz === (clk1 & clk2); + | ^~~ ... See the manual at https://verilator.org/verilator_doc.html for more assistance. diff --git a/test_regress/t/t_tri_and_eqcase.v b/test_regress/t/t_tri_and_eqcase.v index 204aab82d..1c4b09a14 100644 --- a/test_regress/t/t_tri_and_eqcase.v +++ b/test_regress/t/t_tri_and_eqcase.v @@ -6,7 +6,7 @@ module t (clk1, clk2); input wire clk1, clk2; - logic b = 1'z === (clk1 & clk2); + logic b = 1'bz === (clk1 & clk2); always begin if (!b) begin diff --git a/test_regress/t/t_tri_inout.cpp b/test_regress/t/t_tri_inout.cpp index 8ce60aa11..8ce735b75 100644 --- a/test_regress/t/t_tri_inout.cpp +++ b/test_regress/t/t_tri_inout.cpp @@ -36,7 +36,7 @@ int main() { bool pass = true; Verilated::debug(0); - tb = new Vt_tri_inout{"tb"}; + tb = new VM_PREFIX{"tb"}; // loop through every possibility and check the result for (tb->SEL = 0; tb->SEL < 2; tb->SEL++) { diff --git a/test_regress/t/t_tri_inz.cpp b/test_regress/t/t_tri_inz.cpp index eccd5eaac..816533dd3 100644 --- a/test_regress/t/t_tri_inz.cpp +++ b/test_regress/t/t_tri_inz.cpp @@ -34,7 +34,7 @@ void check(int d, int en, int exp0, int exp1, int expx, int expz) { int main() { Verilated::debug(0); - tb = new Vt_tri_inz{"tb"}; + tb = new VM_PREFIX{"tb"}; check(0, 1, 1, 0, 0, 0); check(1, 1, 0, 1, 0, 0); check(0, 0, 0, 0, 0, 1); diff --git a/test_regress/t/t_tri_pullup.cpp b/test_regress/t/t_tri_pullup.cpp index 84fc351d1..f900d0b06 100644 --- a/test_regress/t/t_tri_pullup.cpp +++ b/test_regress/t/t_tri_pullup.cpp @@ -46,7 +46,7 @@ bool check() { int main() { Verilated::debug(0); - tb = new Vt_tri_pullup{"tb"}; + tb = new VM_PREFIX{"tb"}; // loop through every possibility and check the result bool pass = true; diff --git a/test_regress/t/t_tri_select.cpp b/test_regress/t/t_tri_select.cpp index ff31b307d..b3fc80f98 100644 --- a/test_regress/t/t_tri_select.cpp +++ b/test_regress/t/t_tri_select.cpp @@ -44,7 +44,7 @@ bool check() { int main() { Verilated::debug(0); - tb = new Vt_tri_select{"tb"}; + tb = new VM_PREFIX{"tb"}; // loop through every possibility and check the result bool pass = true; diff --git a/test_regress/t/t_type_compare.pl b/test_regress/t/t_type_compare.pl new file mode 100755 index 000000000..a17622844 --- /dev/null +++ b/test_regress/t/t_type_compare.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2004 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_type_compare.v b/test_regress/t/t_type_compare.v new file mode 100644 index 000000000..a209dffee --- /dev/null +++ b/test_regress/t/t_type_compare.v @@ -0,0 +1,68 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module Sub #(parameter type T = type(logic[11:0])); +endmodule + +module t; + + int case_ok; + + Sub #(.T(int)) sub(); + + typedef logic [12:0] logic12_t; + + // Generate if + if (type(logic[12:0]) !== type(logic[12:0])) initial $stop; + if (type(logic[12:0]) != type(logic12_t)) initial $stop; + if (type(logic[12:0]) !== type(logic12_t)) initial $stop; + if (type(logic[22:0]) == type(logic12_t)) initial $stop; + if (type(logic[22:0]) === type(logic12_t)) initial $stop; + // Generate case + case (type(real)) + type(int): initial $stop; + type(real): ; + default: initial $stop; + endcase + + initial begin + if (type(real) == type(logic[12:0])) $stop; + if (type(real) === type(logic[12:0])) $stop; + if (type(real) != type(real)) $stop; + if (type(real) !== type(real)) $stop; + if (type(logic[12:0]) !== type(logic[12:0])) $stop; + if (type(logic[12:0]) != type(logic12_t)) $stop; + if (type(logic[12:0]) !== type(logic12_t)) $stop; + if (type(logic[22:0]) == type(logic12_t)) $stop; + if (type(logic[22:0]) === type(logic12_t)) $stop; + + // Item selected + case (type(real)) + type(real): case_ok = 1; + type(int): $stop; + type(chandle): $stop; + default: $stop; + endcase + if (case_ok != 1) $stop; + + // Default selected + case (type(real)) + type(int): $stop; + default: case_ok = 2; + endcase + if (case_ok != 2) $stop; + + // No body selected + case (type(real)) + type(int): $stop; + endcase + if (case_ok != 2) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_type_compare_bad.out b/test_regress/t/t_type_compare_bad.out new file mode 100644 index 000000000..e3827de74 --- /dev/null +++ b/test_regress/t/t_type_compare_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_type_compare_bad.v:12:9: Case(type) statement requires items that have type() items + : ... In instance t + 12 | 1: $stop; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_union_unpacked_bad.pl b/test_regress/t/t_type_compare_bad.pl similarity index 100% rename from test_regress/t/t_union_unpacked_bad.pl rename to test_regress/t/t_type_compare_bad.pl diff --git a/test_regress/t/t_type_compare_bad.v b/test_regress/t/t_type_compare_bad.v new file mode 100644 index 000000000..1b22fabb3 --- /dev/null +++ b/test_regress/t/t_type_compare_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + initial begin + // Syntax error, so not checking: if (type(real) == 1)) $stop; // Bad + + case (type(real)) + 1: $stop; // Bad + default: $finish; + endcase + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_unbounded_bad.out b/test_regress/t/t_unbounded_bad.out index bd98ae872..c21431950 100644 --- a/test_regress/t/t_unbounded_bad.out +++ b/test_regress/t/t_unbounded_bad.out @@ -3,9 +3,9 @@ 9 | if ($) $stop; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Warning-WIDTH: t/t_unbounded_bad.v:9:7: Logical operator IF expects 1 bit on the If, but If's UNBOUNDED generates 32 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_unbounded_bad.v:9:7: Logical operator IF expects 1 bit on the If, but If's UNBOUNDED generates 32 bits. + : ... In instance t 9 | if ($) $stop; | ^~ - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_unicode.pl b/test_regress/t/t_unicode.pl index 836641e83..2708b48d1 100755 --- a/test_regress/t/t_unicode.pl +++ b/test_regress/t/t_unicode.pl @@ -14,21 +14,27 @@ use vars qw($Self); scenarios(simulator => 1); +# Greek Hi +my $hi = "Greek: " . c(0xce) . c(0xb3) . c(0xce) . c(0xb5) . c(0xce) . c(0xb9) . c(0xce) . c(0xb1); +sub c { + # Appease https://www.virustotal.com NANO-Antivirus gives Trojan.Script.Vbs-heuristic flag + my $code = shift; + return eval("c" . "h" . "r(" . $code . ")"); +} + sub gen { my $filename = shift; my $fh = IO::File->new(">$filename"); - $fh->print(chr(0xEF).chr(0xBB).chr(0xBF)); # BOM + $fh->print(c(0xEF)); + $fh->print(c(0xBB)); + $fh->print(c(0xBF)); # BOM $fh->print("// Bom\n"); $fh->print("// Generated by t_unicode.pl\n"); $fh->print("module t;\n"); - $fh->print(" // Chinese " - . chr(0xe8) . chr(0xaf) . chr(0x84) . chr(0xe8) . chr(0xae) . chr(0xba) # Comment - . "\n"); + $fh->print(" // " . $hi . "\n"); $fh->print(" initial begin\n"); - $fh->print(" \$write(\"Hello " - . chr(0xe4) . chr(0xb8) . chr(0x96) . chr(0xe7) . chr(0x95) . chr(0x8c) # World - . "\\n\");\n"); + $fh->print(" \$write(\"" . $hi . "\\n\");\n"); $fh->print(" \$write(\"*-* All Finished *-*\\n\");\n"); $fh->print(" \$finish;\n"); $fh->print(" end\n"); @@ -44,7 +50,7 @@ compile( execute( check_finished => 1, - expect => q{Hello \344\270\226\347\225\214.*}, + expect => $hi, ); ok(1); diff --git a/test_regress/t/t_union_unpacked.pl b/test_regress/t/t_union_unpacked.pl new file mode 100755 index 000000000..859050d63 --- /dev/null +++ b/test_regress/t/t_union_unpacked.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_union_unpacked.v b/test_regress/t/t_union_unpacked.v new file mode 100644 index 000000000..1cc8d341b --- /dev/null +++ b/test_regress/t/t_union_unpacked.v @@ -0,0 +1,26 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + union { + bit [7:0] val1; + bit [3:0] val2; + real r; + } u; + + initial begin + u.val1 = 8'h7c; + if (u.val1 != 8'h7c) $stop; + if (u.val2 != 4'hc) $stop; + u.r = 1.24; + if (u.r != 1.24) $stop; + $display("%p", u); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_union_unpacked_bad.out b/test_regress/t/t_union_unpacked_bad.out deleted file mode 100644 index 783f81c13..000000000 --- a/test_regress/t/t_union_unpacked_bad.out +++ /dev/null @@ -1,7 +0,0 @@ -%Warning-UNPACKED: t/t_union_unpacked_bad.v:9:12: Unsupported: Unpacked union - : ... In instance x - 9 | typedef union { - | ^~~~~ - ... For warning description see https://verilator.org/warn/UNPACKED?v=latest - ... Use "/* verilator lint_off UNPACKED */" and lint_on around source to disable this message. -%Error: Exiting due to diff --git a/test_regress/t/t_unopt_combo_isolate.pl b/test_regress/t/t_unopt_combo_isolate.pl index cbc33dab8..c875fbf2b 100755 --- a/test_regress/t/t_unopt_combo_isolate.pl +++ b/test_regress/t/t_unopt_combo_isolate.pl @@ -19,11 +19,11 @@ compile( if ($Self->{vlt_all}) { file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+5/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_unopt_combo_isolate_vlt.pl b/test_regress/t/t_unopt_combo_isolate_vlt.pl index f8aa4fcc3..dedfa5e76 100755 --- a/test_regress/t/t_unopt_combo_isolate_vlt.pl +++ b/test_regress/t/t_unopt_combo_isolate_vlt.pl @@ -19,11 +19,11 @@ compile( if ($Self->{vlt_all}) { file_grep($Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+5/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); - file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); + file_grep("$out_filename", qr/\/i); } execute( diff --git a/test_regress/t/t_unpacked_concat_bad.out b/test_regress/t/t_unpacked_concat_bad.out index 1482e7507..0f7ec60dd 100644 --- a/test_regress/t/t_unpacked_concat_bad.out +++ b/test_regress/t/t_unpacked_concat_bad.out @@ -3,4 +3,8 @@ 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; | ^ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: t/t_unpacked_concat_bad.v:17:46: Assignment pattern missed initializing elements: 0 + : ... In instance t + 17 | localparam bit_int_t count_bits [1:0] = {2{$bits(count_t)}}; + | ^ %Error: Exiting due to diff --git a/test_regress/t/t_unpacked_init.pl b/test_regress/t/t_unpacked_init.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_unpacked_init.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2019 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_unpacked_init.v b/test_regress/t/t_unpacked_init.v new file mode 100644 index 000000000..ae7243ad1 --- /dev/null +++ b/test_regress/t/t_unpacked_init.v @@ -0,0 +1,32 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define stop $stop +`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0) + +module t (/*AUTOARG*/); + + int a1[2] = '{12, 13}; + int a2[2] = {14, 15}; + int a3[1] = '{16}; + int a4[1] = {17}; + + initial begin + `checkh(a1[0], 12); + `checkh(a1[1], 13); + + `checkh(a2[0], 14); + `checkh(a2[1], 15); + + `checkh(a3[0], 16); + + `checkh(a4[0], 17); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_var_in_assign_pedantic.pl b/test_regress/t/t_var_in_assign_pedantic.pl new file mode 100755 index 000000000..205a9bca8 --- /dev/null +++ b/test_regress/t/t_var_in_assign_pedantic.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2005 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_var_in_assign_bad.v"); + +lint( + verilator_flags2 => ['-Wpedantic -Wno-fatal'], + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_nonamebegin.v b/test_regress/t/t_var_nonamebegin.v index 164e5a3b8..2c366c5dd 100644 --- a/test_regress/t/t_var_nonamebegin.v +++ b/test_regress/t/t_var_nonamebegin.v @@ -67,7 +67,7 @@ module t (/*AUTOARG*/ $finish; end - task tsk; + task automatic tsk; integer t1; $display("t1 {mod}.tsk %m"); begin diff --git a/test_regress/t/t_var_pins_sc1.pl b/test_regress/t/t_var_pins_sc1.pl index 6e7485b34..88e6143c4 100755 --- a/test_regress/t/t_var_pins_sc1.pl +++ b/test_regress/t/t_var_pins_sc1.pl @@ -18,27 +18,27 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc2.pl b/test_regress/t/t_var_pins_sc2.pl index 8edb72dbd..9cb732256 100755 --- a/test_regress/t/t_var_pins_sc2.pl +++ b/test_regress/t/t_var_pins_sc2.pl @@ -18,27 +18,27 @@ compile( ); { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc32.pl b/test_regress/t/t_var_pins_sc32.pl index 6f202e8b5..f3b956e98 100755 --- a/test_regress/t/t_var_pins_sc32.pl +++ b/test_regress/t/t_var_pins_sc32.pl @@ -18,27 +18,27 @@ compile( ); { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc64.pl b/test_regress/t/t_var_pins_sc64.pl index 9414d82d4..370dc90a3 100755 --- a/test_regress/t/t_var_pins_sc64.pl +++ b/test_regress/t/t_var_pins_sc64.pl @@ -18,27 +18,27 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1_vlt;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16_vlt;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc_biguint.pl b/test_regress/t/t_var_pins_sc_biguint.pl index 05ac18ba4..226882081 100755 --- a/test_regress/t/t_var_pins_sc_biguint.pl +++ b/test_regress/t/t_var_pins_sc_biguint.pl @@ -18,27 +18,27 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i128;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i513;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o128;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o513;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc_uint.pl b/test_regress/t/t_var_pins_sc_uint.pl index e7b965c3a..4a60aed89 100755 --- a/test_regress/t/t_var_pins_sc_uint.pl +++ b/test_regress/t/t_var_pins_sc_uint.pl @@ -18,27 +18,27 @@ compile( ); { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i128;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i513;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o128;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o513;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16;/x); } execute(); diff --git a/test_regress/t/t_var_pins_sc_uint_biguint.pl b/test_regress/t/t_var_pins_sc_uint_biguint.pl index 64b7075a7..1aae8b505 100755 --- a/test_regress/t/t_var_pins_sc_uint_biguint.pl +++ b/test_regress/t/t_var_pins_sc_uint_biguint.pl @@ -18,27 +18,27 @@ compile( ); { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i128;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i513;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o128;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o513;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o128;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o513;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16;/x); } execute(); diff --git a/test_regress/t/t_var_pins_scui.pl b/test_regress/t/t_var_pins_scui.pl index a0d81d189..6162561fd 100755 --- a/test_regress/t/t_var_pins_scui.pl +++ b/test_regress/t/t_var_pins_scui.pl @@ -18,23 +18,23 @@ compile( ); if ($Self->{vlt_all}) { - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in \s+ &i64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &i65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in\s> \s+ &ibv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in \s+ &i64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &i65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_in\s> \s+ &ibv16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o8;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o16;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o32;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out \s+ &o64;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &o65;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv1;/x); - file_grep("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out\s> \s+ &obv16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o8;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o16;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o32;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out \s+ &o64;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &o65;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv1;/x); + file_grep("$Self->{obj_dir}/$Self->{vm_prefix}.h", qr/sc_out\s> \s+ &obv16;/x); } execute(); diff --git a/test_regress/t/t_var_port_xml.pl b/test_regress/t/t_var_port_xml.pl index acd3ab33d..fe03f41d4 100755 --- a/test_regress/t/t_var_port_xml.pl +++ b/test_regress/t/t_var_port_xml.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; compile( - verilator_flags2 => ['--xml-only'], + verilator_flags2 => ['--no-std', '--xml-only'], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/test_regress/t/t_var_sc_bv.cpp b/test_regress/t/t_var_sc_bv.cpp index 24e4ab7d7..306810635 100644 --- a/test_regress/t/t_var_sc_bv.cpp +++ b/test_regress/t/t_var_sc_bv.cpp @@ -54,7 +54,7 @@ int main() #endif { Verilated::debug(0); - tb = new VM_PREFIX("tb"); + tb = new VM_PREFIX{"tb"}; VlWide<8> /*255:0*/ input_var; VlWide<8> /*255:0*/ out_var; diff --git a/test_regress/t/t_var_static.out b/test_regress/t/t_var_static.out deleted file mode 100644 index 01e0c2fa9..000000000 --- a/test_regress/t/t_var_static.out +++ /dev/null @@ -1,14 +0,0 @@ -%Error-UNSUPPORTED: t/t_var_static.v:20:18: Unsupported: 'static' function/task variables - : ... In instance t - 20 | static int st = 2; st++; return st; - | ^~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error-UNSUPPORTED: t/t_var_static.v:30:18: Unsupported: 'static' function/task variables - : ... In instance t - 30 | static int st = 2; st++; return st; - | ^~ -%Error-UNSUPPORTED: t/t_var_static.v:40:18: Unsupported: 'static' function/task variables - : ... In instance t - 40 | static int st = 2; st++; return st; - | ^~ -%Error: Exiting due to diff --git a/test_regress/t/t_var_static.pl b/test_regress/t/t_var_static.pl index dc589151c..93a3a1be3 100755 --- a/test_regress/t/t_var_static.pl +++ b/test_regress/t/t_var_static.pl @@ -12,13 +12,11 @@ scenarios(simulator => 1); compile( verilator_flags2 => ['-Wno-IMPLICITSTATIC'], - fails => $Self->{vlt_all}, # Verilator unsupported, bug546 - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_var_static.v b/test_regress/t/t_var_static.v index 8dbc698ff..cb54f6a0c 100644 --- a/test_regress/t/t_var_static.v +++ b/test_regress/t/t_var_static.v @@ -6,6 +6,16 @@ `define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); +function automatic int f_au_st_global (); + static int st = 0; st++; return st; +endfunction + +package my_pkg; + function int f_no_st_pkg (); + static int st = 0; st++; return st; + endfunction +endpackage + module t (/*AUTOARG*/ // Inputs clk @@ -67,6 +77,11 @@ module t (/*AUTOARG*/ v = f_au_au(); `checkh(v, 3); v = f_au_au(); `checkh(v, 3); // + v = f_au_st_global(); `checkh(v, 1); + v = f_au_st_global(); `checkh(v, 2); + v = my_pkg::f_no_st_pkg(); `checkh(v, 1); + v = my_pkg::f_no_st_pkg(); `checkh(v, 2); + // end int cyc = 0; diff --git a/test_regress/t/t_var_static_param.out b/test_regress/t/t_var_static_param.out deleted file mode 100644 index 2a08df190..000000000 --- a/test_regress/t/t_var_static_param.out +++ /dev/null @@ -1,6 +0,0 @@ -%Error-UNSUPPORTED: t/t_var_static_param.v:33:18: Unsupported: 'static' function/task variables - : ... In instance t.subb - 33 | static int st = 2; st += P; return st; - | ^~ - ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: Exiting due to diff --git a/test_regress/t/t_var_static_param.pl b/test_regress/t/t_var_static_param.pl index 8d48ddb75..b46d46042 100755 --- a/test_regress/t/t_var_static_param.pl +++ b/test_regress/t/t_var_static_param.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, # Verilator unsupported, bug546 - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_var_xref_bad.out b/test_regress/t/t_var_xref_bad.out new file mode 100644 index 000000000..7ae4ada15 --- /dev/null +++ b/test_regress/t/t_var_xref_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_var_xref_bad.v:11:12: Found definition of 'tsk' as a TASK but expected a scope/variable + 11 | initial tsk.bad_missing_ref = 0; + | ^~~ +%Error: Exiting due to diff --git a/test_regress/t/t_var_xref_bad.pl b/test_regress/t/t_var_xref_bad.pl new file mode 100755 index 000000000..59ba0d6c6 --- /dev/null +++ b/test_regress/t/t_var_xref_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_var_xref_bad.v b/test_regress/t/t_var_xref_bad.v new file mode 100644 index 000000000..ec7be7c09 --- /dev/null +++ b/test_regress/t/t_var_xref_bad.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + task tsk; + endtask + + initial tsk.bad_missing_ref = 0; +endmodule diff --git a/test_regress/t/t_vlcov_info.out b/test_regress/t/t_vlcov_info.out index 40b3c320b..bb304d511 100644 --- a/test_regress/t/t_vlcov_info.out +++ b/test_regress/t/t_vlcov_info.out @@ -1,4 +1,4 @@ TN:verilator_coverage SF:file1.sp -DA:159,53 +DA:159,1 end_of_record diff --git a/test_regress/t/t_vlt_warn_bad.out b/test_regress/t/t_vlt_warn_bad.out index f8f64f115..e4520566e 100644 --- a/test_regress/t/t_vlt_warn_bad.out +++ b/test_regress/t/t_vlt_warn_bad.out @@ -1,7 +1,7 @@ -%Warning-WIDTH: t/t_vlt_warn.v:21:33: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits. - : ... In instance t +%Warning-WIDTHTRUNC: t/t_vlt_warn.v:21:33: Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits. + : ... In instance t 21 | reg width_warn3_var_line20 = 2'b11; | ^~~~~ - ... For warning description see https://verilator.org/warn/WIDTH?v=latest - ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. + ... For warning description see https://verilator.org/warn/WIDTHTRUNC?v=latest + ... Use "/* verilator lint_off WIDTHTRUNC */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_vpi_get_public_rw_switch.pl b/test_regress/t/t_vpi_get_public_rw_switch.pl index 3a0123177..203665b14 100755 --- a/test_regress/t/t_vpi_get_public_rw_switch.pl +++ b/test_regress/t/t_vpi_get_public_rw_switch.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); skip("Known compiler limitation") if $Self->cxx_version =~ /\(GCC\) 4.4/; -VM_PREFIX("Vt_vpi_get"); +vm_prefix("Vt_vpi_get"); top_filename("t/t_vpi_get.v"); pli_filename("t_vpi_get.cpp"); diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 09ff0af06..aded57047 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -256,7 +256,7 @@ int main(int argc, char** argv) { uint64_t sim_time = 1100; contextp->debug(0); contextp->commandArgs(argc, argv); - // we're going to be checking for these errors do don't crash out + // We're going to be checking for these errors so don't crash out contextp->fatalOnVpiError(0); const std::unique_ptr topp{new VM_PREFIX{contextp.get(), diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 650c7f55f..955464d11 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -120,7 +120,7 @@ int mon_check() { CHECK_RESULT_NZ(mod2); const char* mod_a_name = vpi_get_str(vpiName, mod2); - CHECK_RESULT_CSTR(mod_a_name, "mod_a"); + CHECK_RESULT_CSTR(mod_a_name, "\\mod.a "); TestVpiHandle it3 = vpi_iterate(vpiModule, mod2); CHECK_RESULT_NZ(it3); @@ -129,13 +129,13 @@ int mon_check() { CHECK_RESULT_NZ(mod3); const char* mod_c_name = vpi_get_str(vpiName, mod3); - if (std::strcmp(mod_c_name, "mod_b") == 0) { + if (std::strcmp(mod_c_name, "\\mod_b$ ") == 0) { // Full visibility in other simulators, skip mod_b TestVpiHandle mod4 = vpi_scan(it3); CHECK_RESULT_NZ(mod4); mod_c_name = vpi_get_str(vpiName, mod4); } - CHECK_RESULT_CSTR(mod_c_name, "mod_c."); + CHECK_RESULT_CSTR(mod_c_name, "\\mod\\c$ "); return 0; // Ok } @@ -177,7 +177,7 @@ int main(int argc, char** argv) { uint64_t sim_time = 1100; contextp->debug(0); contextp->commandArgs(argc, argv); - // we're going to be checking for these errors do don't crash out + // We're going to be checking for these errors so don't crash out contextp->fatalOnVpiError(0); { diff --git a/test_regress/t/t_vpi_module.v b/test_regress/t/t_vpi_module.v index b997270f1..be1d4a46c 100644 --- a/test_regress/t/t_vpi_module.v +++ b/test_regress/t/t_vpi_module.v @@ -31,7 +31,7 @@ extern "C" int mon_check(); wire a, b, x; - A mod_a(/*AUTOINST*/ + A \mod.a (/*AUTOINST*/ // Outputs .x (x), // Inputs @@ -72,14 +72,14 @@ module A(/*AUTOARG*/ wire y, c; - B mod_b(/*AUTOINST*/ + B \mod_b$ (/*AUTOINST*/ // Outputs .y (y), // Inputs .b (b), .c (c)); - C \mod_c. (/*AUTOINST*/ + C \mod\c$ (/*AUTOINST*/ // Outputs .x (x), // Inputs diff --git a/test_regress/t/t_vpi_module_dpi.pl b/test_regress/t/t_vpi_module_dpi.pl index 25189b715..3dcaa1ef1 100755 --- a/test_regress/t/t_vpi_module_dpi.pl +++ b/test_regress/t/t_vpi_module_dpi.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); skip("Known compiler limitation") if $Self->cxx_version =~ /\(GCC\) 4.4/; -VM_PREFIX("Vt_vpi_module"); +vm_prefix("Vt_vpi_module"); top_filename("t/t_vpi_module.v"); pli_filename("t_vpi_module.cpp"); diff --git a/test_regress/t/t_vpi_module_empty.cpp b/test_regress/t/t_vpi_module_empty.cpp new file mode 100644 index 000000000..139ff4cce --- /dev/null +++ b/test_regress/t/t_vpi_module_empty.cpp @@ -0,0 +1,123 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2010-2023 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#ifdef IS_VPI + +#include "vpi_user.h" + +#include + +#else + +#include "verilated.h" +#include "verilated_vcd_c.h" +#include "verilated_vpi.h" + +#include "Vt_vpi_module_empty.h" +#include "Vt_vpi_module_empty__Dpi.h" +#include "svdpi.h" + +#endif + +#include +#include +#include + +// These require the above. Comment prevents clang-format moving them +#include "TestSimulator.h" +#include "TestVpi.h" + +// __FILE__ is too long +#define FILENM "t_vpi_module_empty.cpp" + +#define DEBUG \ + if (0) printf + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \ + return __LINE__; \ + } + +extern "C" { +int mon_check() { +#ifdef TEST_VERBOSE + printf("-mon_check()\n"); +#endif + + TestVpiHandle it = vpi_iterate(vpiModule, NULL); + CHECK_RESULT_NZ(it); + return 0; // Ok +} +} +//====================================================================== + +#ifdef IS_VPI + +static int mon_check_vpi() { + TestVpiHandle href = vpi_handle(vpiSysTfCall, 0); + s_vpi_value vpi_value; + + vpi_value.format = vpiIntVal; + vpi_value.value.integer = mon_check(); + vpi_put_value(href, &vpi_value, NULL, vpiNoDelay); + + return 0; +} + +static s_vpi_systf_data vpi_systf_data[] = {{vpiSysFunc, vpiIntFunc, (PLI_BYTE8*)"$mon_check", + (PLI_INT32(*)(PLI_BYTE8*))mon_check_vpi, 0, 0, 0}, + 0}; + +// cver entry +void vpi_compat_bootstrap(void) { + p_vpi_systf_data systf_data_p; + systf_data_p = &(vpi_systf_data[0]); + while (systf_data_p->type != 0) vpi_register_systf(systf_data_p++); +} + +// icarus entry +void (*vlog_startup_routines[])() = {vpi_compat_bootstrap, 0}; + +#else + +int main(int argc, char** argv) { + const std::unique_ptr contextp{new VerilatedContext}; + + uint64_t sim_time = 1100; + contextp->debug(0); + contextp->commandArgs(argc, argv); + // we're going to be checking for these errors do don't crash out + contextp->fatalOnVpiError(0); + + // Test second construction + const std::unique_ptr topp{new VM_PREFIX{contextp.get(), + // Note null name - we're flattening it out + ""}}; + +#ifdef VERILATOR +#ifdef TEST_VERBOSE + contextp->scopesDump(); +#endif +#endif + + topp->eval(); + VerilatedVpi::callValueCbs(); + TestVpiHandle vh = vpi_handle_by_name((PLI_BYTE8*)"top.sv_if_i.a", NULL); + CHECK_RESULT_NZ(vh); + TestVpiHandle it = vpi_iterate(vpiModule, NULL); + CHECK_RESULT_NZ(it); + + topp->final(); + return 0; +} + +#endif diff --git a/test_regress/t/t_vpi_module_empty.pl b/test_regress/t/t_vpi_module_empty.pl new file mode 100755 index 000000000..d9362b696 --- /dev/null +++ b/test_regress/t/t_vpi_module_empty.pl @@ -0,0 +1,30 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2010 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +skip("Known compiler limitation") + if $Self->cxx_version =~ /\(GCC\) 4.4/; + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + iv_flags2 => ["-g2005-sv"], + verilator_flags2 => ["+define+USE_DOLLAR_C32 --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_module_empty.cpp"], + ); + +execute( + use_libvpi => 1, + check_finished => 1 + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_module_empty.v b/test_regress/t/t_vpi_module_empty.v new file mode 100644 index 000000000..cd0f78d34 --- /dev/null +++ b/test_regress/t/t_vpi_module_empty.v @@ -0,0 +1,25 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2023 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +interface sv_if(); + logic a /*verilator public_flat_rw*/; +endinterface + +module top (); + + sv_if sv_if_i(); + + // Workaround for bug3937: + // logic d /*verilator public_flat_rw*/; + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_vpi_param.cpp b/test_regress/t/t_vpi_param.cpp index 12feae1fd..8d769ae26 100644 --- a/test_regress/t/t_vpi_param.cpp +++ b/test_regress/t/t_vpi_param.cpp @@ -245,7 +245,7 @@ int main(int argc, char** argv) { uint64_t sim_time = 1100; contextp->debug(0); contextp->commandArgs(argc, argv); - // we're going to be checking for these errors do don't crash out + // We're going to be checking for these errors so don't crash out contextp->fatalOnVpiError(0); const std::unique_ptr topp{new VM_PREFIX{contextp.get(), diff --git a/test_regress/t/t_vpi_unimpl.cpp b/test_regress/t/t_vpi_unimpl.cpp index da925d42b..7c7f17cdf 100644 --- a/test_regress/t/t_vpi_unimpl.cpp +++ b/test_regress/t/t_vpi_unimpl.cpp @@ -189,7 +189,7 @@ int main(int argc, char** argv) { uint64_t sim_time = 1100; contextp->commandArgs(argc, argv); // contextp->debug(9); - // we're going to be checking for these errors do don't crash out + // We're going to be checking for these errors so don't crash out contextp->fatalOnVpiError(0); const std::unique_ptr topp{new VM_PREFIX{contextp.get(), diff --git a/test_regress/t/t_vpi_var.cpp b/test_regress/t/t_vpi_var.cpp index 5f28eb0d5..470af16de 100644 --- a/test_regress/t/t_vpi_var.cpp +++ b/test_regress/t/t_vpi_var.cpp @@ -19,8 +19,14 @@ #include "verilated_vcd_c.h" #include "verilated_vpi.h" +#ifdef T_VPI_VAR2 +#include "Vt_vpi_var2.h" +#include "Vt_vpi_var2__Dpi.h" +#else #include "Vt_vpi_var.h" #include "Vt_vpi_var__Dpi.h" +#endif + #include "svdpi.h" #endif @@ -267,6 +273,25 @@ int _mon_check_var() { TestVpiHandle vh3 = vpi_handle_by_name((PLI_BYTE8*)"onebit", vh2); CHECK_RESULT_NZ(vh3); +#ifdef T_VPI_VAR2 + // test scoped attributes + TestVpiHandle vh_invisible1 = vpi_handle_by_name((PLI_BYTE8*)"invisible1", vh2); + CHECK_RESULT_Z(vh_invisible1); + + TestVpiHandle vh_invisible2 = vpi_handle_by_name((PLI_BYTE8*)"invisible2", vh2); + CHECK_RESULT_Z(vh_invisible2); + + TestVpiHandle vh_visibleParam1 = vpi_handle_by_name((PLI_BYTE8*)"visibleParam1", vh2); + CHECK_RESULT_NZ(vh_visibleParam1); + + TestVpiHandle vh_invisibleParam1 = vpi_handle_by_name((PLI_BYTE8*)"invisibleParam1", vh2); + CHECK_RESULT_Z(vh_invisibleParam1); + + TestVpiHandle vh_visibleParam2 = vpi_handle_by_name((PLI_BYTE8*)"visibleParam2", vh2); + CHECK_RESULT_NZ(vh_visibleParam2); + +#endif + // onebit attributes PLI_INT32 d; d = vpi_get(vpiType, vh3); @@ -389,6 +414,8 @@ int _mon_check_varlist() { int _mon_check_getput() { TestVpiHandle vh2 = VPI_HANDLE("onebit"); CHECK_RESULT_NZ(vh2); + const char* p = vpi_get_str(vpiFullName, vh2); + CHECK_RESULT_CSTR(p, "t.onebit"); s_vpi_value v; v.format = vpiIntVal; @@ -399,15 +426,68 @@ int _mon_check_getput() { t.type = vpiSimTime; t.high = 0; t.low = 0; + v.value.integer = 0; + vpi_put_value(vh2, &v, &t, vpiNoDelay); + vpi_get_value(vh2, &v); + CHECK_RESULT(v.value.integer, 0); + v.value.integer = 1; vpi_put_value(vh2, &v, &t, vpiNoDelay); - vpi_get_value(vh2, &v); CHECK_RESULT(v.value.integer, 1); return 0; } +int _mon_check_var_long_name() { + TestVpiHandle vh2 = VPI_HANDLE( + "LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_" + "a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND"); + CHECK_RESULT_NZ(vh2); + const char* p = vpi_get_str(vpiFullName, vh2); + CHECK_RESULT_CSTR(p, "t.LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_" + "which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_" + "long_name_which_will_get_hashed_LONGEND"); + return 0; +} + +int _mon_check_getput_iter() { + TestVpiHandle vh2 = VPI_HANDLE("sub"); + CHECK_RESULT_NZ(vh2); + TestVpiHandle vh10 = vpi_iterate(vpiReg, vh2); + CHECK_RESULT_NZ(vh10); + CHECK_RESULT(vpi_get(vpiType, vh10), vpiIterator); + + TestVpiHandle vh11; + while (1) { + vh11 = vpi_scan(vh10); + CHECK_RESULT_NZ(vh11); // If get zero we never found the variable + const char* p = vpi_get_str(vpiFullName, vh11); +#ifdef TEST_VERBOSE + printf(" scanned %s\n", p); +#endif + if (0 == strcmp(p, "t.sub.subsig1")) break; + } + CHECK_RESULT(vpi_get(vpiType, vh11), vpiReg); + + s_vpi_time t; + t.type = vpiSimTime; + t.high = 0; + t.low = 0; + s_vpi_value v; + v.format = vpiIntVal; + v.value.integer = 0; + vpi_put_value(vh11, &v, &t, vpiNoDelay); + vpi_get_value(vh11, &v); + CHECK_RESULT(v.value.integer, 0); + + v.value.integer = 1; + vpi_put_value(vh11, &v, &t, vpiNoDelay); + vpi_get_value(vh11, &v); + CHECK_RESULT(v.value.integer, 1); + return 0; +} + int _mon_check_quad() { TestVpiHandle vh2 = VPI_HANDLE("quads"); CHECK_RESULT_NZ(vh2); @@ -605,6 +685,12 @@ int _mon_check_putget_str(p_cb_data cb_data) { = vpi_handle_by_name((PLI_BYTE8*)"verbose", data[i].scope)); } + for (int i = 1; i <= 6; i++) { + char buf[32]; + snprintf(buf, sizeof(buf), TestSimulator::rooted("subs[%d].subsub"), i); + CHECK_RESULT_NZ(data[i].scope = vpi_handle_by_name((PLI_BYTE8*)buf, NULL)); + } + static t_cb_data cb_data; static s_vpi_value v; TestVpiHandle count_h = VPI_HANDLE("count"); @@ -650,7 +736,9 @@ extern "C" int mon_check() { if (int status = _mon_check_value_callbacks()) return status; if (int status = _mon_check_var()) return status; if (int status = _mon_check_varlist()) return status; + if (int status = _mon_check_var_long_name()) return status; if (int status = _mon_check_getput()) return status; + if (int status = _mon_check_getput_iter()) return status; if (int status = _mon_check_quad()) return status; if (int status = _mon_check_string()) return status; if (int status = _mon_check_putget_str(NULL)) return status; diff --git a/test_regress/t/t_vpi_var.v b/test_regress/t/t_vpi_var.v index 672f987fc..ebc707eb3 100644 --- a/test_regress/t/t_vpi_var.v +++ b/test_regress/t/t_vpi_var.v @@ -28,6 +28,7 @@ extern "C" int mon_check(); reg onebit /*verilator public_flat_rw @(posedge clk) */; reg [2:1] twoone /*verilator public_flat_rw @(posedge clk) */; reg [2:1] fourthreetwoone[4:3] /*verilator public_flat_rw @(posedge clk) */; + reg LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND /*verilator public_flat_rw*/; // verilator lint_off LITENDIAN reg [0:61] quads[2:3] /*verilator public_flat_rw @(posedge clk) */; @@ -95,12 +96,20 @@ extern "C" int mon_check(); generate for (i=1; i<=6; i=i+1) begin : arr arr #(.LENGTH(i)) arr(); - end endgenerate + end + endgenerate + + genvar k; + generate + for (k=1; k<=6; k=k+1) begin : subs + sub subsub(); + end + endgenerate endmodule : t module sub; - reg subsig1 /*verilator public_flat_rd*/; + reg subsig1 /*verilator public_flat_rw*/; reg subsig2 /*verilator public_flat_rd*/; `ifdef IVERILOG // stop icarus optimizing signals away diff --git a/test_regress/t/t_vpi_var2.pl b/test_regress/t/t_vpi_var2.pl new file mode 100755 index 000000000..cb4a3acb8 --- /dev/null +++ b/test_regress/t/t_vpi_var2.pl @@ -0,0 +1,31 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +pli_filename("t_vpi_var.cpp"); +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + sim_time => 2100, + iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI -DWAVES -DT_VPI_VAR2"], + v_flags2 => ["+define+USE_VPI_NOT_DPI"], + verilator_flags2 => ["--exe --vpi --no-l2name $Self->{t_dir}/t_vpi_var.cpp"], + ); + +execute( + use_libvpi => 1, + check_finished => 1, + all_run_flags => ['+PLUS +INT=1234 +STRSTR'] + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_var2.v b/test_regress/t/t_vpi_var2.v new file mode 100644 index 000000000..ca24c06f2 --- /dev/null +++ b/test_regress/t/t_vpi_var2.v @@ -0,0 +1,158 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2023 by Wilson Snyder. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`ifdef USE_VPI_NOT_DPI +//We call it via $c so we can verify DPI isn't required - see bug572 +`else +import "DPI-C" context function int mon_check(); +`endif + +module t +/* verilator public_flat_on */ +#( + parameter int visibleParam1 = 0, +/* verilator public_off */ + parameter int invisibleParam1 = 1, +/* verilator public_on */ + parameter int visibleParam2 = 2 +/* verilator public_off */ +) +(/*AUTOARG*/ + // Inputs + clk + ); + +`ifdef VERILATOR +`systemc_header +extern "C" int mon_check(); +`verilog +`endif + + input clk; +/*verilator public_flat_rw_on @(posedge clk)*/ + reg onebit; + reg [2:1] twoone; + reg [2:1] fourthreetwoone[4:3]; + reg LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND; + // verilator lint_off LITENDIAN + reg [0:61] quads[2:3] /*verilator public_flat_rw @(posedge clk)*/; +/*verilator public_off*/ + reg invisible1; + // verilator lint_on LITENDIAN + +/*verilator public_flat_rd_on*/ + reg [31:0] count; + reg [31:0] half_count; +/*verilator public_off*/ + reg invisible2; + +/*verilator public_flat_rw_on @(posedge clk)*/ + reg [7:0] text_byte; + reg [15:0] text_half; + reg [31:0] text_word; + reg [63:0] text_long; + reg [511:0] text; +/*verilator public_off*/ + integer status; + + sub sub(); + + // Test loop + initial begin + count = 0; + onebit = 1'b0; + fourthreetwoone[3] = 0; // stop icarus optimizing away + text_byte = "B"; + text_half = "Hf"; + text_word = "Word"; + text_long = "Long64b"; + text = "Verilog Test module"; +`ifdef VERILATOR + status = $c32("mon_check()"); +`endif +`ifdef IVERILOG + status = $mon_check(); +`endif +`ifndef USE_VPI_NOT_DPI + status = mon_check(); +`endif + if (status!=0) begin + $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $stop; + end + $write("%%Info: Checking results\n"); + if (onebit != 1'b1) $stop; + if (quads[2] != 62'h12819213_abd31a1c) $stop; + if (quads[3] != 62'h1c77bb9b_3784ea09) $stop; + if (text_byte != "A") $stop; + if (text_half != "T2") $stop; + if (text_word != "Tree") $stop; + if (text_long != "44Four44") $stop; + if (text != "lorem ipsum") $stop; + end + + always @(posedge clk) begin + count <= count + 2; + if (count[1]) + half_count <= half_count + 2; + + if (count == 1000) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + + genvar i; + generate + for (i=1; i<=6; i=i+1) begin : arr + arr #(.LENGTH(i)) arr(); + end + endgenerate + + genvar k; + generate + for (k=1; k<=6; k=k+1) begin : subs + sub subsub(); + end + endgenerate + +endmodule : t + +module sub; + reg subsig1 /*verilator public_flat_rw*/; + reg subsig2 /*verilator public_flat_rd*/; +`ifdef IVERILOG + // stop icarus optimizing signals away + wire redundant = subsig1 | subsig2; +`endif +endmodule : sub + +module arr; + + parameter LENGTH = 1; + +/*verilator public_flat_rw_on*/ + reg [LENGTH-1:0] sig; + reg [LENGTH-1:0] rfr; + + reg check; + reg verbose; +/*verilator public_off*/ + + initial begin + sig = {LENGTH{1'b0}}; + rfr = {LENGTH{1'b0}}; + end + + always @(posedge check) begin + if (verbose) $display("%m : %x %x", sig, rfr); + if (check && sig != rfr) $stop; + check <= 0; + end + +endmodule : arr diff --git a/test_regress/t/t_vthread.pl b/test_regress/t/t_vthread.pl new file mode 100755 index 000000000..5a360513a --- /dev/null +++ b/test_regress/t/t_vthread.pl @@ -0,0 +1,58 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +use IO::File; + +scenarios(vlt => 1); + +sub gen { + my $filename = shift; + my $n = shift; + + my $fh = IO::File->new(">$filename"); + $fh->print("// Generated by t_vthread.pl\n"); + $fh->print("module genmod #(int val = 0)(clk, o);\n"); + $fh->print(" input clk;\n"); + $fh->print(" output int o;\n"); + $fh->print(" always @ (posedge clk) begin\n"); + $fh->print(" o <= val;\n"); + $fh->print(" end\n"); + $fh->print("endmodule\n"); + $fh->print("module t (clk, o);\n"); + $fh->print(" input clk;\n"); + $fh->print(" output int o;\n"); + for (my $i = 0; $i < ($n + 1); ++$i) { + $fh->print(" int r$i;\n"); + $fh->print(" genmod #(.val($i)) rm$i (.clk(clk), .o(r$i));\n"); + } + $fh->print(" always @ (posedge clk) begin\n"); + $fh->print(" o <= r$n;\n"); + $fh->print(' $write("*-* All Finished *-*\n");', "\n"); + $fh->print(' $finish;', "\n"); + $fh->print(" end\n"); + $fh->print("endmodule\n"); +} + +top_filename("$Self->{obj_dir}/t_vthread.v"); + +gen($Self->{top_filename}, 6000); + +compile( + # use --trace to generate trace files that can be parallelized + verilator_flags2=>["--stats --trace --verilate-jobs 2"], + ); + +execute( + check_finished => 1, + ); + +file_grep($Self->{stats}, qr/Verilate jobs: 2/); + +ok(1); +1; diff --git a/test_regress/t/t_waiveroutput.out b/test_regress/t/t_waiveroutput.out index e0b0f6767..5e18d8676 100644 --- a/test_regress/t/t_waiveroutput.out +++ b/test_regress/t/t_waiveroutput.out @@ -7,7 +7,7 @@ // 2. Keep the waiver permanently if you are sure this is okay // 3. Keep the waiver temporarily to suppress the output -// lint_off -rule WIDTH -file "*t/t_waiveroutput.v" -match "Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits." +// lint_off -rule WIDTHTRUNC -file "*t/t_waiveroutput.v" -match "Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits." // lint_off -rule UNUSEDSIGNAL -file "*t/t_waiveroutput.v" -match "Signal is not used: 'width_warn'" diff --git a/test_regress/t/t_xml_debugcheck.pl b/test_regress/t/t_xml_debugcheck.pl index 4d1491a1b..1894252fe 100755 --- a/test_regress/t/t_xml_debugcheck.pl +++ b/test_regress/t/t_xml_debugcheck.pl @@ -15,7 +15,7 @@ my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; top_filename("t/t_enum_type_methods.v"); compile( - verilator_flags2 => ['--debug-check', '--flatten'], + verilator_flags2 => ['--no-std', '--debug-check', '--flatten'], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/test_regress/t/t_xml_first.pl b/test_regress/t/t_xml_first.pl index cd9490294..d25c191ff 100755 --- a/test_regress/t/t_xml_first.pl +++ b/test_regress/t/t_xml_first.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; compile( - verilator_flags2 => ['--xml-only'], + verilator_flags2 => ['--no-std', '--xml-only'], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/test_regress/t/t_xml_flat.pl b/test_regress/t/t_xml_flat.pl index dd19fee39..9d4890c52 100755 --- a/test_regress/t/t_xml_flat.pl +++ b/test_regress/t/t_xml_flat.pl @@ -15,7 +15,7 @@ my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; top_filename("t/t_xml_first.v"); compile( - verilator_flags2 => ['--xml-only', '--flatten'], + verilator_flags2 => ['--no-std', '--xml-only', '--flatten'], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/test_regress/t/t_xml_flat_no_inline_mod.pl b/test_regress/t/t_xml_flat_no_inline_mod.pl index 9c51c5674..9763b0cc1 100755 --- a/test_regress/t/t_xml_flat_no_inline_mod.pl +++ b/test_regress/t/t_xml_flat_no_inline_mod.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; compile( - verilator_flags2 => ['--xml-only', '--flatten'], + verilator_flags2 => ['--no-std', '--xml-only', '--flatten'], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/test_regress/t/t_xml_flat_pub_mod.pl b/test_regress/t/t_xml_flat_pub_mod.pl index 9c51c5674..9763b0cc1 100755 --- a/test_regress/t/t_xml_flat_pub_mod.pl +++ b/test_regress/t/t_xml_flat_pub_mod.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; compile( - verilator_flags2 => ['--xml-only', '--flatten'], + verilator_flags2 => ['--no-std', '--xml-only', '--flatten'], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/test_regress/t/t_xml_flat_vlvbound.pl b/test_regress/t/t_xml_flat_vlvbound.pl index 9c51c5674..9763b0cc1 100755 --- a/test_regress/t/t_xml_flat_vlvbound.pl +++ b/test_regress/t/t_xml_flat_vlvbound.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; compile( - verilator_flags2 => ['--xml-only', '--flatten'], + verilator_flags2 => ['--no-std', '--xml-only', '--flatten'], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/test_regress/t/t_xml_output.pl b/test_regress/t/t_xml_output.pl index f6126c66f..8f7f7dc3e 100755 --- a/test_regress/t/t_xml_output.pl +++ b/test_regress/t/t_xml_output.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); my $out_filename = "$Self->{obj_dir}/renamed-$Self->{name}.xml"; compile( - verilator_flags2 => ["--xml-only --xml-output $out_filename"], + verilator_flags2 => ["--no-std", "--xml-only --xml-output $out_filename"], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/test_regress/t/t_xml_tag.pl b/test_regress/t/t_xml_tag.pl index cd9490294..d25c191ff 100755 --- a/test_regress/t/t_xml_tag.pl +++ b/test_regress/t/t_xml_tag.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); my $out_filename = "$Self->{obj_dir}/V$Self->{name}.xml"; compile( - verilator_flags2 => ['--xml-only'], + verilator_flags2 => ['--no-std', '--xml-only'], verilator_make_gmake => 0, make_top_shell => 0, make_main => 0, diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index 6b2338662..ae36b961e 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -19,7 +19,8 @@ # ###################################################################### -cmake_minimum_required(VERSION 3.8) +cmake_minimum_required(VERSION 3.12) +cmake_policy(SET CMP0074 NEW) # Prefer VERILATOR_ROOT from environment if (DEFINED ENV{VERILATOR_ROOT}) @@ -77,6 +78,10 @@ if (NOT CMAKE_CXX_COMPILER_ID MATCHES MSVC) endif() endif() +if (${CMAKE_CXX_COMPILER_ID} STREQUAL "AppleClang") + add_link_options(-Wl,-U,__Z15vl_time_stamp64v,-U,__Z13sc_time_stampv) +endif() + define_property(TARGET PROPERTY VERILATOR_THREADED BRIEF_DOCS "Deprecated and has no effect (ignored)" @@ -142,9 +147,13 @@ function(verilate TARGET) endif() if (NOT VERILATE_PREFIX) + list(LENGTH VERILATE_SOURCES NUM_SOURCES) + if (${NUM_SOURCES} GREATER 1) + message(WARNING "Specify PREFIX if there are multiple SOURCES") + endif() list(GET VERILATE_SOURCES 0 TOPSRC) get_filename_component(_SRC_NAME ${TOPSRC} NAME_WE) - set(VERILATE_PREFIX V${_SRC_NAME}) + string(MAKE_C_IDENTIFIER V${_SRC_NAME} VERILATE_PREFIX) endif() if (VERILATE_TOP_MODULE)