diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ca1b4f3f7..fba21f0da 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,7 +16,6 @@ env: CI_COMMIT: ${{ github.sha }} CCACHE_COMPRESS: 1 CCACHE_DIR: ${{ github.workspace }}/.ccache - CCACHE_MAXSIZE: 2Gi # 2GiB for clang and gcc, 4GiB in total jobs: @@ -31,7 +30,7 @@ jobs: - id: generate name: Run 'generate_matrix.sh' run: | - if [ '${{ github.event_name}}' = 'pull_request' ]; then + if [ '${{ github.event_name }}' = 'pull_request' ]; then matrix='[ "ubuntu-20.04" ]' else matrix='[ "ubuntu-16.04", "ubuntu-18.04", "ubuntu-20.04" ]' @@ -57,7 +56,8 @@ jobs: CI_MAKE_SRC_TARGET: ${{ matrix.debug }} CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cxx }} - CACHE_KEY: ${{ matrix.os }}-${{ matrix.compiler.cc }} + CACHE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.debug }} + CCACHE_MAXSIZE: 256Mi # Per build matrix entry steps: - name: Checkout @@ -77,7 +77,9 @@ jobs: - name: Build run: | + ccache -z ./ci/ci-script.bash + ccache -s tar cvzf verilator-${{ matrix.os}}-${CI_COMMIT}-${{ matrix.compiler.cc }}-${{ matrix.debug }}.tgz ./bin - uses: actions/upload-artifact@v2 @@ -89,7 +91,6 @@ jobs: needs: [ Matrix, Build ] strategy: fail-fast: false - max-parallel: 8 matrix: os: ${{ fromJson(needs.Matrix.outputs.matrix) }} compiler: @@ -98,6 +99,7 @@ jobs: suite: - dist-vlt-0 - dist-vlt-1 + - dist-vlt-2 - vltmt-0 - vltmt-1 runs-on: ${{ matrix.os }} @@ -107,7 +109,8 @@ jobs: CI_RUNS_ON: ${{ matrix.os }} CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cxx }} - CACHE_KEY: ${{ matrix.os }}-${{ matrix.compiler.cc }} + CACHE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.suite }} + CCACHE_MAXSIZE: 256Mi # Per build matrix entry steps: - name: Checkout @@ -134,4 +137,7 @@ jobs: - name: Test env: TESTS: ${{ matrix.suite }} - run: ./ci/ci-script.bash + run: | + ccache -z + ./ci/ci-script.bash + ccache -s diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 81ce290f8..42c0d40cb 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -13,7 +13,6 @@ env: CI_COMMIT: ${{ github.sha }} CCACHE_COMPRESS: 1 CCACHE_DIR: ${{ github.workspace }}/.ccache - CCACHE_MAXSIZE: 2Gi # 2GiB for clang and gcc, 4GiB in total COVERAGE: 1 jobs: @@ -24,7 +23,8 @@ jobs: env: CI_BUILD_STAGE_NAME: build CI_RUNS_ON: ubuntu-20.04 - CACHE_KEY: ubuntu-20.04-${{ matrix.compiler.cc }}-coverage + CACHE_KEY: coverage-build + CCACHE_MAXSIZE: 512Mi steps: - name: Checkout @@ -37,7 +37,7 @@ jobs: with: path: ${{ github.workspace }}/.ccache key: ${{ env.CACHE_KEY }}-${{ env.cache-name }}-${{ github.sha }} - restore-keys: coverage-${{ env.cache-name }} + restore-keys: ${{ env.CACHE_KEY }}-${{ env.cache-name }} - name: Install packages for build env: @@ -46,7 +46,9 @@ jobs: - name: Build run: | + ccache -z ./ci/ci-script.bash + ccache -s tar cvzf verilator-${CI_COMMIT}-coverage.tgz bin src/obj*/*.o src/obj*/*.gcno - uses: actions/upload-artifact@v2 @@ -80,7 +82,8 @@ jobs: env: CI_BUILD_STAGE_NAME: test CI_RUNS_ON: ubuntu-20.04 - CACHE_KEY: ubuntu-20.04-${{ matrix.compiler.cc }}-coverage + CACHE_KEY: coverage-test-${{ matrix.test }}${{ matrix.num }} + CCACHE_MAXSIZE: 512Mi # Per build matrix entry steps: - name: Checkout @@ -93,7 +96,7 @@ jobs: with: path: ${{ github.workspace }}/.ccache key: ${{ env.CACHE_KEY }}-${{ env.cache-name }}-${{ github.sha }} - restore-keys: coverage-${{ env.cache-name }} + restore-keys: ${{ env.CACHE_KEY }}-${{ env.cache-name }} - uses: actions/download-artifact@v2 @@ -106,4 +109,7 @@ jobs: - name: Test env: TESTS: coverage-${{ matrix.test }}${{ matrix.num }} - run: ./ci/ci-script.bash + run: | + ccache -z + ./ci/ci-script.bash + ccache -s diff --git a/.github/workflows/clang-format.yml b/.github/workflows/format.yml similarity index 93% rename from .github/workflows/clang-format.yml rename to .github/workflows/format.yml index 88a3c897c..6d6d68887 100644 --- a/.github/workflows/clang-format.yml +++ b/.github/workflows/format.yml @@ -1,7 +1,7 @@ # DESCRIPTION: Github actions config # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -name: clang-format +name: format on: push: @@ -38,6 +38,6 @@ jobs: - name: Push run: | if [ -n "$(git status --porcelain)" ]; then - git commit . -m "Apply clang-format" && + git commit . -m "Apply 'make format'" && git push origin fi diff --git a/Changes b/Changes index 3a0460c94..d0d49ab8d 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,41 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 4.204 2021-06-12 +========================== + +**Minor:** + +* Add 'make ccache-report' (#3011). [Geza Lore] +* Add --reloop-limit argument (#2943) (#2960). [Geza Lore] +* Add --expand-limit argument (#3005). [Julien Margetts] +* Add TRACE_THREADS to CMake (#2934). [Jonathan Drolet] +* Optimize large lookup tables to static data (#2925). [Geza Lore] +* Optimize reloop to accept constant index offsets (#2939). [Geza Lore] +* Split always blocks to better respect --output-split-cfuncs. [Geza Lore] +* Support ignoring "`pragma protect ..." (#2886). [Udi Finkelstein] +* Support --trace-fst for SystemC with CMake (#2927). [Jonathan Drolet] +* Update cmake latest C++ Standard Compilation flag (#2951). [Ameya Vikram Singh] +* Prep work towards better ccache hashing/performance. [Geza Lore] +* Fix assertion failure in bitOpTree optimization (#2891) (#2899). [Raynard Qiao] +* Fix DPI functions not seen as vpiModule (#2893). [Todd Strader] +* Fix bounds check in VL_SEL_IWII (#2910). [Krzysztof Bieganski] +* Fix slowdown in elaboration (#2911). [Nathan Graybeal] +* Fix initialization of assoc in assoc array (#2914). [myftptoyman] +* Fix make support for gmake 3.x (#2920) (#2921). [Philipp Wagner] +* Fix VPI memory access for packed arrays (#2922). [Todd Strader] +* Fix MCD close also closing stdout (#2931). [Alexander Grobman] +* Fix split procedures to better respect --output-split-cfuncs (#2942). [Geza Lore] +* Fix to emit 'else if' without nesting (#2944). [Geza Lore] +* Fix part select issues in LATCH warning (#2948) (#2938). [Julien Margetts] +* Fix to not emit empty files with low split limits (#2961). [Geza Lore] +* Fix merging of assignments in C++ code (#2970). [Ruper Swarbrick] +* Fix unused variable warnings (#2991). [Pieter Kapsenberg] +* Fix --protect-ids when using SV classes (#2994). [Geza Lore] +* Fix constant function calls with uninit value (#2995). [yanx21] +* Fix Makefiles to support Windows EXEEXT usage (#3008). [Miodrag Milanovic] + + Verilator 4.202 2021-04-24 ========================== @@ -331,7 +366,7 @@ Verilator 4.034 2020-05-03 * Support event data type (with some restrictions). * Support $root. (#2150) [Keyi Zhang] * Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated. -* Fix build of fast path tracing code to use OPT_FAST. (#2245) [Geza Lore] +* Add support of --trace-structs for CMake (#2986). [Martin Schmidt] * Fix arrayed instances connecting to slices. (#2263) [Don/engr248] * Fix error on unpacked connecting to packed. (#2288) [Joseph Shaker] * Fix logical not optimization with empty begin. (#2291) [Baltazar Ortiz] diff --git a/Makefile.in b/Makefile.in index 0e0d7607a..fcee49bca 100644 --- a/Makefile.in +++ b/Makefile.in @@ -44,6 +44,7 @@ srcdir = @srcdir@ VPATH = @srcdir@ HOST = @HOST@ +EXEEXT = @EXEEXT@ DOXYGEN = doxygen INSTALL = @INSTALL@ @@ -130,6 +131,7 @@ DISTFILES1 = $(INFOS) .gitignore \ verilator-config.cmake.in \ verilator-config-version.cmake.in \ bin/verilator \ + bin/verilator_ccache_report \ bin/verilator_coverage \ bin/verilator_difftree \ bin/verilator_gantt \ @@ -193,6 +195,7 @@ DISTFILES2 = \ INST_PROJ_FILES = \ bin/verilator \ + bin/verilator_ccache_report \ bin/verilator_coverage \ bin/verilator_gantt \ bin/verilator_includer \ @@ -203,9 +206,9 @@ INST_PROJ_FILES = \ include/vltstd/*.[chv]* \ INST_PROJ_BIN_FILES = \ - bin/verilator_bin \ - bin/verilator_bin_dbg \ - bin/verilator_coverage_bin_dbg \ + bin/verilator_bin$(EXEEXT) \ + bin/verilator_bin_dbg$(EXEEXT) \ + bin/verilator_coverage_bin_dbg$(EXEEXT) \ EXAMPLES_FIRST = \ examples/make_hello_c \ @@ -221,10 +224,10 @@ all: all_nomsg msg_test all_nomsg: verilator_exe $(VL_INST_MAN_FILES) .PHONY:verilator_exe -.PHONY:verilator_bin -.PHONY:verilator_bin_dbg -.PHONY:verilator_coverage_bin_dbg -verilator_exe verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg: +.PHONY:verilator_bin$(EXEEXT) +.PHONY:verilator_bin_dbg$(EXEEXT) +.PHONY:verilator_coverage_bin_dbg$(EXEEXT) +verilator_exe verilator_bin$(EXEEXT) verilator_bin_dbg$(EXEEXT) verilator_coverage_bin_dbg$(EXEEXT): @echo ------------------------------------------------------------ @echo "making verilator in src" $(MAKE) -C src $(OBJCACHE_JOBS) $(CI_MAKE_SRC_TARGET) @@ -280,8 +283,8 @@ verilator.pdf: Makefile $(MAKE) -C docs verilator.pdf # See uninstall also - don't put wildcards in this variable, it might uninstall other stuff -VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg \ - verilator_coverage verilator_gantt verilator_includer verilator_profcfunc +VL_INST_BIN_FILES = verilator verilator_bin$(EXEEXT) verilator_bin_dbg$(EXEEXT) verilator_coverage_bin_dbg$(EXEEXT) \ + verilator_ccache_report verilator_coverage verilator_gantt verilator_includer verilator_profcfunc # Some scripts go into both the search path and pkgdatadir, # so they can be found by the user, and under $VERILATOR_ROOT. @@ -305,11 +308,12 @@ installbin: ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_coverage $(DESTDIR)$(bindir)/verilator_coverage ) ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_gantt $(DESTDIR)$(bindir)/verilator_gantt ) ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc ) - ( cd bin ; $(INSTALL_PROGRAM) verilator_bin $(DESTDIR)$(bindir)/verilator_bin ) - ( cd bin ; $(INSTALL_PROGRAM) verilator_bin_dbg $(DESTDIR)$(bindir)/verilator_bin_dbg ) - ( cd bin ; $(INSTALL_PROGRAM) verilator_coverage_bin_dbg $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg ) + ( cd bin ; $(INSTALL_PROGRAM) verilator_bin$(EXEEXT) $(DESTDIR)$(bindir)/verilator_bin$(EXEEXT) ) + ( cd bin ; $(INSTALL_PROGRAM) verilator_bin_dbg$(EXEEXT) $(DESTDIR)$(bindir)/verilator_bin_dbg$(EXEEXT) ) + ( cd bin ; $(INSTALL_PROGRAM) verilator_coverage_bin_dbg$(EXEEXT) $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg$(EXEEXT) ) $(MKINSTALLDIRS) $(DESTDIR)$(pkgdatadir)/bin ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer ) + ( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_ccache_report $(DESTDIR)$(pkgdatadir)/bin/verilator_ccache_report ) # Man files can either be part of the original kit, or built in current directory # So important we use $^ so VPATH is searched @@ -458,7 +462,7 @@ clang-tidy: $(CLANGTIDY_DEP) analyzer-src: -rm -rf src/obj_dbg - scan-build $(MAKE) -k verilator_coverage_bin_dbg verilator_bin_dbg + scan-build $(MAKE) -k verilator_coverage_bin_dbg$(EXEEXT) verilator_bin_dbg$(EXEEXT) analyzer-include: -rm -rf examples/*/obj* @@ -476,12 +480,12 @@ clang-format: $(CLANGFORMAT) $(CLANGFORMAT_FLAGS) $(CLANGFORMAT_FILES) PY_PROGRAMS = \ + bin/verilator_ccache_report \ examples/xml_py/vl_file_copy \ examples/xml_py/vl_hier_graph \ docs/guide/conf.py \ - docs/guide/vl_sphinx_extract \ - docs/guide/vl_sphinx_extract \ - docs/guide/vl_doxygen_filter \ + docs/bin/vl_sphinx_extract \ + docs/bin/vl_sphinx_fix \ src/astgen \ src/bisonpre \ src/config_rev \ diff --git a/bin/verilator b/bin/verilator index 9e1ce7094..61064a9b4 100755 --- a/bin/verilator +++ b/bin/verilator @@ -315,6 +315,7 @@ detailed descriptions of these arguments. -E Preprocess, but do not compile --error-limit Abort after this number of errors --exe Link to create executable + --expand-limit Set expand optimization limit -F Parse arguments from a file, relatively -f Parse arguments from a file -FI Force include of a file @@ -378,6 +379,7 @@ detailed descriptions of these arguments. --quiet-exit Don't print the command on failure --relative-includes Resolve includes relative to current file --no-relative-cfuncs Disallow 'this->' in generated functions + --reloop-limit Minimum iterations for forming loops --report-unoptflat Extra diagnostics for UNOPTFLAT --rr Run Verilator and record with rr --savable Enable model save-restore diff --git a/bin/verilator_ccache_report b/bin/verilator_ccache_report new file mode 100755 index 000000000..764accd27 --- /dev/null +++ b/bin/verilator_ccache_report @@ -0,0 +1,93 @@ +#!/usr/bin/env python3 +# pylint: disable=C0103,C0114,C0115,C0116,C0123,C0301,R0902,R0913,R0914,R0912,R0915,W0621 +###################################################################### + +import argparse +import collections +import pathlib +import re + +from datetime import datetime + +parser = argparse.ArgumentParser( + allow_abbrev=False, + formatter_class=argparse.RawDescriptionHelpFormatter, + description="""Report ccache behavior of a Verilated model build.""", + epilog= + """Copyright 2002-2021 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""") + +parser.add_argument('-o', + type=argparse.FileType('w'), + metavar="OUTFILE", + required=True, + help='output file') +parser.add_argument('logdir', type=pathlib.Path, help='log directory') + +args = parser.parse_args() + +results = {} +elapsed = {} + + +def toDateTime(s): + return datetime.strptime(s, "%Y-%m-%dT%H:%M:%S.%f") + + +for logfile in args.logdir.iterdir(): + with logfile.open() as fh: + start = None + obj = None + for line in fh: + line = line.strip() + match = re.match(r'\[(\S+)\s.*Object file: (.*)$', line) + if match: + start = toDateTime(match.group(1)) + obj = match.group(2) + match = re.match(r'\[(\S+)\s.*Result: (.*)$', line) + if match: + assert obj is not None + elapsed[obj] = toDateTime(match.group(1)) - start + results[obj] = match.group(2) + +args.o.write("#" * 80 + "\n") +args.o.write("ccache report (from verilator_ccache_report) :\n") + +if not results: + args.o.write("\nAll object files up to date\n") +else: + args.o.write("\nCompiled object files:\n") + wnames = max(len(_) for _ in results) + 1 + wresults = max(len(_) for _ in results.values()) + 1 + for k in sorted(results.keys()): + args.o.write("{:{wnames}} : {:{wresults}} : {}s\n".format( + k, + results[k], + elapsed[k].total_seconds(), + wnames=wnames, + wresults=wresults)) + + args.o.write("\nSummary:\n") + counts = collections.Counter(_ for _ in results.values()) + total = sum(counts.values()) + for k in sorted(counts.keys()): + c = counts[k] + args.o.write("{:{width}}| {} ({:.2%})\n".format(k, + c, + c / total, + width=wresults)) + + args.o.write("\nLongest:\n") + longest = sorted(list(elapsed.items()), + key=lambda kv: -kv[1].total_seconds()) + for i, (k, v) in enumerate(longest): + args.o.write("{:{width}}| {}s\n".format(k, + v.total_seconds(), + width=wnames)) + if i > 4: break + +args.o.write("#" * 80 + "\n") diff --git a/ci/ci-script.bash b/ci/ci-script.bash index 498531eed..70ded6d2c 100755 --- a/ci/ci-script.bash +++ b/ci/ci-script.bash @@ -85,10 +85,13 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then # Run the specified test case $TESTS in dist-vlt-0) - "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=0/2 + "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=0/3 ;; dist-vlt-1) - "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=1/2 + "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=1/3 + ;; + dist-vlt-2) + "$MAKE" -C test_regress SCENARIOS="--dist --vlt $sanitize" DRIVER_HASHSET=--hashset=2/3 ;; vltmt-0) "$MAKE" -C test_regress SCENARIOS=--vltmt DRIVER_HASHSET=--hashset=0/2 diff --git a/configure.ac b/configure.ac index fce513b17..ee5043af4 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.202 2021-04-24], +AC_INIT([Verilator],[4.204 2021-06-12], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file @@ -272,13 +272,15 @@ AC_DEFUN([_MY_LDLIBS_CHECK_OPT], # Flag to select newest language standard supported # Macros work such that first option that passes is the one we take -# gnu++17 code is clean, but SystemC in 2018 doesn't link with it (bug1339) -# gnu++14 is the newest that Verilator supports +# Currently enabled gnu++14/c++14 due to packaged SystemC dependency +# gnu++17 is the newest that Verilator supports # std++03 is the oldest that Verilator supports +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++20) #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++17) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++14) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++11) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=gnu++03) +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++20) #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++17) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++14) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_NEWEST,-std=c++11) @@ -289,11 +291,13 @@ AC_SUBST(CFG_CXXFLAGS_STD_NEWEST) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++03) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++11) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++14) -#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=std++17) +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++17) +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=c++20) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++03) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++11) _MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++14) #_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++17) +#_MY_CXX_CHECK_SET(CFG_CXXFLAGS_STD_OLDEST,-std=gnu++20) AC_SUBST(CFG_CXXFLAGS_STD_OLDEST) # Flags for compiling Verilator internals including parser, and Verilated files diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index f8c20a846..1da70dd75 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -6,6 +6,7 @@ Please see the Verilator manual for 200+ additional contributors. Thanks to all. Ahmed El-Mahmoudy Alex Chadwick Àlex Torregrosa +Ameya Vikram Singh Andreas Kuster Chris Randall Conor McCullough @@ -38,6 +39,7 @@ Jean Berniolles Jeremy Bennett John Coiner John Demme +Jonathan Drolet Josh Redford Julien Margetts Kaleb Barrett @@ -53,9 +55,11 @@ Marco Widmer Markus Krause Marlon James Marshal Qiao +Martin Schmidt Matthew Ballance Michael Killough Mike Popoloski +Miodrag Milanović Morten Borup Petersen Nandu Raj Nathan Kohagen diff --git a/docs/bin/vl_sphinx_extract b/docs/bin/vl_sphinx_extract index 068ad8b35..1b2c27d07 100755 --- a/docs/bin/vl_sphinx_extract +++ b/docs/bin/vl_sphinx_extract @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# pylint: disable=C0112,C0114,C0116,C0301,R0903 +# pylint: disable=C0112,C0114,C0115,C0116,C0301,R0201,R0903 # -*- Python -*- See copyright, etc below ###################################################################### @@ -8,6 +8,7 @@ import re ####################################################################### + class VlSphinxExtract: debug = 0 SkipBasenames = {} diff --git a/docs/bin/vl_sphinx_fix b/docs/bin/vl_sphinx_fix index cedbc0d63..ed6d06107 100755 --- a/docs/bin/vl_sphinx_fix +++ b/docs/bin/vl_sphinx_fix @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -# pylint: disable=C0112,C0114,C0116,C0301,R0903 +# pylint: disable=C0112,C0114,C0115,C0116,C0301,R0903 # -*- Python -*- See copyright, etc below ###################################################################### diff --git a/docs/gen/ex_MULTIDRIVEN_faulty.rst b/docs/gen/ex_MULTIDRIVEN_faulty.rst new file mode 100644 index 000000000..0be24327d --- /dev/null +++ b/docs/gen/ex_MULTIDRIVEN_faulty.rst @@ -0,0 +1,11 @@ +.. comment: generated by t_lint_multidriven_bad +.. code-block:: sv + :linenos: + :emphasize-lines: 2,5 + + always @(posedge clk) begin + out2[7:0] <= d0; // <--- Warning + end + always @(negedge clk) begin + out2[15:8] <= d0; // <--- Warning + end diff --git a/docs/gen/ex_MULTIDRIVEN_msg.rst b/docs/gen/ex_MULTIDRIVEN_msg.rst new file mode 100644 index 000000000..a2b090f34 --- /dev/null +++ b/docs/gen/ex_MULTIDRIVEN_msg.rst @@ -0,0 +1,6 @@ +.. comment: generated by t_lint_multidriven_bad +.. code-block:: + + %Warning-MULTIDRIVEN: example.v:1:22 Signal has multiple driving blocks with different clocking: 'out2' + example.v:1:7 ... Location of first driving block + example.v:1:7 ... Location of other driving block diff --git a/docs/guide/conf.py b/docs/guide/conf.py index 1d30f1d51..060d7a106 100644 --- a/docs/guide/conf.py +++ b/docs/guide/conf.py @@ -1,4 +1,4 @@ -# pylint: disable=E402 +# pylint: disable=C0103,C0114,C0116,E0402,W0622 # # Configuration file for Verilator's Sphinx documentation builder. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 @@ -12,11 +12,10 @@ from datetime import datetime import os import re -import shutil import sys sys.path.insert(0, os.path.abspath('./_ext')) -import sphinx_rtd_theme +import sphinx_rtd_theme # pylint: disable=wrong-import-position, def get_vlt_version(): @@ -94,7 +93,7 @@ today_fmt = datetime.now().strftime("%F") # If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = True -# TODO could use this for internals<->guide references +# Could use this for internals<->guide references # intersphinx_mapping = { 'sphinx': ('https://sphinx-doc.org/', None), } # ---------------------------------------------------------------------- @@ -208,7 +207,7 @@ spelling_ignore_contributor_names = True # ---------------------------------------------------------------------- # -- Options for doxygen -#if shutil.which("doxygen"): +# if shutil.which("doxygen"): # breathe_projects = { # "verilated": "../_build/doxygen/verilated/xml", # } diff --git a/docs/guide/exe_verilator.rst b/docs/guide/exe_verilator.rst index f7cf6dbd4..d7eebe90d 100644 --- a/docs/guide/exe_verilator.rst +++ b/docs/guide/exe_verilator.rst @@ -403,6 +403,12 @@ Summary: files on the command line that implement the main loop for your simulation. +.. option:: --expand-limit + + Rarely needed. Fine-tune optimizations to set the maximum size of an + expression in 32-bit words to expand into separate word-based + statements. + .. option:: -F Read the specified file, and act as if all text inside it was specified @@ -418,8 +424,11 @@ Summary: fairly standard across Verilog tools. The file may contain :code:`//` comments which are ignored to the end of - the line. Any :code:`$VAR`, :code:`$(VAR)`, or :code:`${VAR}` will be - replaced with the specified environment variable. + the line. It may also contain :code:`/* .. */` comments which are + ignored, be cautious that wildcards are not handled in -f files, and + that :code:`directory/*` is the beginning of a comment, not a wildcard. + Any :code:`$VAR`, :code:`$(VAR)`, or :code:`${VAR}` will be replaced + with the specified environment variable. .. option:: -FI @@ -915,6 +924,15 @@ Summary: the path of the referencing file, instead of relative to the current directory. +.. option:: --reloop-limit + + Rarely needed. Verilator attempts to turn some common sequences of + statements into loops in the output. This argument specifies the minimum + number of iterations the resulting loop needs to have in order to perform + this transformation. Default limit is 40. A smaller number may slightly + improve C++ compilation time on designs where these sequences are common, + however effect on model performance requires benchmarking. + .. option:: --report-unoptflat Extra diagnostics for UNOPTFLAT warnings. This includes for each loop, diff --git a/docs/guide/faq.rst b/docs/guide/faq.rst index ca99d5e7e..c3ffd5b76 100644 --- a/docs/guide/faq.rst +++ b/docs/guide/faq.rst @@ -118,9 +118,9 @@ A. Pass the :vlopt:`--trace` option to Verilator, and in your top level C B. Or, for finer-grained control, or C++ files with multiple Verilated modules you may also create the trace purely from C++. Create a - VerilatedVcdC object, and in your main loop call - ``trace_object->dump(time)`` every time step, and finally call - ``trace_object->close()``. + VerilatedVcdC object, and in your main loop right after ``eval()`` call + ``trace_object->dump(contextp->time())`` every time step, and finally + call ``trace_object->close()``. .. code-block:: C++ :emphasize-lines: 1,5-8,12 @@ -128,15 +128,17 @@ B. Or, for finer-grained control, or C++ files with multiple Verilated #include "verilated_vcd_c.h" ... int main(int argc, char** argv, char** env) { + const std::unique_ptr contextp{new VerilatedContext}; ... Verilated::traceEverOn(true); VerilatedVcdC* tfp = new VerilatedVcdC; topp->trace(tfp, 99); // Trace 99 levels of hierarchy tfp->open("obj_dir/t_trace_ena_cc/simx.vcd"); ... - while (Verilated::time() < sim_time && !Verilated::gotFinish()) { - Verilated::timeInc(1); - tfp->dump(main_time); + while (contextp->time() < sim_time && !contextp->gotFinish()) { + contextp->timeInc(1); + topp->eval(); + tfp->dump(contextp->time()); } tfp->close(); } @@ -385,7 +387,7 @@ How do I get faster build times? identical source builds, even across different users. If ccache was installed when Verilator was built it is used, or see OBJCACHE environment variable to override this. Also see the - :vlopt:`--output-split` option. + :vlopt:`--output-split` option and :ref: `Profiling ccache efficiency` * To reduce the compile time of classes that use a Verilated module (e.g. a top CPP file) you may wish to add a diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index 39ebf1464..3033a5c22 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -316,6 +316,35 @@ statistics. For more information see :command:`verilator_gantt`. +.. _Profiling ccache efficiency: + +Profiling ccache efficiency +=========================== + +The Verilator generated Makefile provides support for basic profiling of +ccache behavior during the build. This can be used to track down files that +might be unnecessarily rebuilt, though as of today even small code changes +will usually require rebuilding a large number of files. Improving ccache +efficiency during the edit/compile/test loop is an active area of +development. + +To get a basic report of how well ccache is doing, add the `ccache-report` +target when invoking the generated Makefile: + +.. code-block:: bash + + make -C obj_dir -f Vout.mk Vout ccache-report + +This will print a report based on all executions of ccache during this +invocation of Make. The report is also written to a file, in this example +`obj_dir/Vout__cache_report.txt`. + +To use the `ccache-report` target, at least one other explicit build target +must be specified, and OBJCACHE must be set to 'ccache'. + +This feature is currently experimental and might change in subsequent +releases. + .. _Save/Restore: Save/Restore diff --git a/docs/guide/verilating.rst b/docs/guide/verilating.rst index 53810b67e..d1231a314 100644 --- a/docs/guide/verilating.rst +++ b/docs/guide/verilating.rst @@ -360,7 +360,8 @@ Verilate in CMake verilate(target SOURCES source ... [TOP_MODULE top] [PREFIX name] [TRACE] [TRACE_FST] [SYSTEMC] [COVERAGE] [INCLUDE_DIRS dir ...] [OPT_SLOW ...] [OPT_FAST ...] - [OPT_GLOBAL ..] [DIRECTORY dir] [VERILATOR_ARGS ...]) + [OPT_GLOBAL ..] [DIRECTORY dir] [THREADS num] + [TRACE_THREADS num] [VERILATOR_ARGS ...]) Lowercase and ... should be replaced with arguments, the uppercase parts delimit the arguments and can be passed in any order, or left out entirely @@ -429,6 +430,15 @@ SystemC include directories and link to the SystemC libraries. the SystemC library. This can be specified using the SYSTEMC_CXX_FLAGS environment variable. +.. describe:: THREADS + + Optional. Generated a multi-threaded model, same as "--threads". + +.. describe:: TRACE_THREADS + + Optional. Generated multi-threaded trace dumping, same as + "--trace-threads". + .. describe:: TOP_MODULE Optional. Sets the name of the top module. Defaults to the name of the diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index ac0ca9329..ee76aeece 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -128,6 +128,13 @@ List Of Warnings simulate correctly. +.. option:: BADSTDPRAGMA + + Error that a pragma is badly formed, when that pragma is defined by IEEE1800-2017. + For example, an empty `pragma line, or an incorrect specified '`pragma protect'. + Note that 3rd party pragmas not defined by IEEE1800-2017 are ignored. + + .. option:: BLKANDNBLK .. TODO better example @@ -796,15 +803,25 @@ List Of Warnings .. option:: MULTIDRIVEN - .. TODO better example + Warns that the specified signal comes from multiple always blocks each + with different clocking. This warning does not look at individual bits + (see example below). - Warns that the specified signal comes from multiple always blocks. This - is often unsupported by synthesis tools, and is considered bad style. - It will also cause longer simulation runtimes due to reduced - optimizations. + This is considered bad style, as the consumer of a given signal may be + unaware of the inconsistent clocking, causing clock domain crossing + or timing bugs. + + Faulty example: + + .. include:: ../../docs/gen/ex_MULTIDRIVEN_faulty.rst + + Results in: + + .. include:: ../../docs/gen/ex_MULTIDRIVEN_msg.rst Ignoring this warning will only slow simulations, it will simulate - correctly. + correctly. It may however cause longer simulation runtimes due to + reduced optimizations. .. option:: MULTITOP @@ -988,6 +1005,16 @@ List Of Warnings a var/reg must be used as the target of procedural assignments. +.. option:: PROTECTED + + Warning that a '`pragma protected' section was encountered. The code + inside the protected region will be partly checked for correctness, but is + otherwise ignored. + + Suppressing the warning may make Verilator differ from a simulator that + accepts the protected code. + + .. option:: RANDC Warns that the :code:`randc` keyword is currently unsupported, and that diff --git a/examples/cmake_hello_sc/CMakeLists.txt b/examples/cmake_hello_sc/CMakeLists.txt index 211b73170..f85d05c6d 100644 --- a/examples/cmake_hello_sc/CMakeLists.txt +++ b/examples/cmake_hello_sc/CMakeLists.txt @@ -20,7 +20,7 @@ # cmake --build . cmake_minimum_required(VERSION 3.8) -project(cmake_hello_sc) +project(cmake_hello_sc CXX) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) if (NOT verilator_FOUND) @@ -37,6 +37,11 @@ find_package(SystemCLanguage QUIET) # Create a new executable target that will contain all your sources add_executable(example ../make_hello_sc/sc_main.cpp) +set_property( + TARGET example + PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD} + ) + # Add the Verilated circuit to the target verilate(example SYSTEMC INCLUDE_DIRS "../make_hello_sc" diff --git a/examples/cmake_tracing_sc/CMakeLists.txt b/examples/cmake_tracing_sc/CMakeLists.txt index eb785d76a..4651d1709 100644 --- a/examples/cmake_tracing_sc/CMakeLists.txt +++ b/examples/cmake_tracing_sc/CMakeLists.txt @@ -20,7 +20,7 @@ # cmake --build . cmake_minimum_required(VERSION 3.8) -project(cmake_tracing_sc_example) +project(cmake_tracing_sc_example CXX) find_package(verilator HINTS $ENV{VERILATOR_ROOT} ${VERILATOR_ROOT}) if (NOT verilator_FOUND) @@ -37,6 +37,11 @@ find_package(SystemCLanguage QUIET) # Create a new executable target that will contain all your sources add_executable(example ../make_tracing_sc/sc_main.cpp) +set_property( + TARGET example + PROPERTY CXX_STANDARD ${SystemC_CXX_STANDARD} + ) + # Add the Verilated circuit to the target verilate(example SYSTEMC COVERAGE TRACE INCLUDE_DIRS "../make_tracing_sc" diff --git a/include/gtkwave/fst_win_unistd.h b/include/gtkwave/fst_win_unistd.h new file mode 100644 index 000000000..15ab2c1fc --- /dev/null +++ b/include/gtkwave/fst_win_unistd.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2009-2018 Tony Bybell. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * SPDX-License-Identifier: MIT + */ + +#ifndef WIN_UNISTD_H +#define WIN_UNISTD_H + +#include +#ifdef _WIN64 +#include +#else +#include +#endif + +#include + +#define ftruncate _chsize_s +#define unlink _unlink +#define fileno _fileno +#define lseek _lseeki64 + +#ifdef _WIN64 +#define ssize_t __int64 +#define SSIZE_MAX 9223372036854775807i64 +#else +#define ssize_t long +#define SSIZE_MAX 2147483647L +#endif + +#include "stdint.h" + +#endif //WIN_UNISTD_H diff --git a/include/gtkwave/fstapi.c b/include/gtkwave/fstapi.c index 3cb4652c9..b4c9823d2 100644 --- a/include/gtkwave/fstapi.c +++ b/include/gtkwave/fstapi.c @@ -80,6 +80,12 @@ #define PATH_MAX (4096) #endif +#if defined(_MSC_VER) +typedef int64_t fst_off_t; +#else +typedef off_t fst_off_t; +#endif + /* note that Judy versus Jenkins requires more experimentation: they are */ /* functionally equivalent though it appears Jenkins is slightly faster. */ /* in addition, Jenkins is not bound by the LGPL. */ @@ -155,8 +161,8 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 #ifdef __MINGW32__ #include #ifndef HAVE_FSEEKO -#define ftello ftell -#define fseeko fseek +#define ftello _ftelli64 +#define fseeko _fseeki64 #endif #endif @@ -284,7 +290,7 @@ static size_t fstFwrite(const void *buf, size_t siz, size_t cnt, FILE *fp) return(fwrite(buf, siz, cnt, fp)); } -static int fstFtruncate(int fd, off_t length) +static int fstFtruncate(int fd, fst_off_t length) { return(ftruncate(fd, length)); } @@ -329,12 +335,12 @@ return(NULL); #define fstMmap(__addr,__len,__prot,__flags,__fd,__off) fstMmap2((__len), (__fd), (__off)) #define fstMunmap(__addr,__len) free(__addr) -static void *fstMmap2(size_t __len, int __fd, off_t __off) +static void *fstMmap2(size_t __len, int __fd, fst_off_t __off) { (void)__off; unsigned char *pnt = (unsigned char *)malloc(__len); -off_t cur_offs = lseek(__fd, 0, SEEK_CUR); +fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR); size_t i; lseek(__fd, 0, SEEK_SET); @@ -734,7 +740,7 @@ FILE *tchn_handle; unsigned char *vchg_mem; -off_t hier_file_len; +fst_off_t hier_file_len; uint32_t *valpos_mem; unsigned char *curval_mem; @@ -754,7 +760,7 @@ unsigned fourpack : 1; unsigned fastpack : 1; int64_t timezero; -off_t section_header_truncpos; +fst_off_t section_header_truncpos; uint32_t tchn_cnt, tchn_idx; uint64_t curtime; uint64_t firsttime; @@ -762,7 +768,7 @@ uint32_t vchg_siz; uint32_t vchg_alloc_siz; uint32_t secnum; -off_t section_start; +fst_off_t section_start; uint32_t numscopes; double nan; /* nan value for uninitialized doubles */ @@ -820,7 +826,7 @@ fstEnumHandle max_enumhandle; }; -static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, off_t offset, int whence) +static int fstWriterFseeko(struct fstWriterContext *xc, FILE *stream, fst_off_t offset, int whence) { int rc = fseeko(stream, offset, whence); @@ -987,7 +993,7 @@ if(pnt == MAP_FAILED) static void fstWriterCreateMmaps(struct fstWriterContext *xc) { -off_t curpos = ftello(xc->handle); +fst_off_t curpos = ftello(xc->handle); fflush(xc->hier_handle); @@ -1041,7 +1047,7 @@ if(xc->curval_mem) { unsigned char *pnt = xc->curval_mem; int __fd = fileno(xc->curval_handle); - off_t cur_offs = lseek(__fd, 0, SEEK_CUR); + fst_off_t cur_offs = lseek(__fd, 0, SEEK_CUR); size_t i; size_t __len = xc->maxvalpos; @@ -1282,14 +1288,14 @@ int cnt = 0; unsigned int i; unsigned char *vchg_mem; FILE *f; -off_t fpos, indxpos, endpos; +fst_off_t fpos, indxpos, endpos; uint32_t prevpos; int zerocnt; unsigned char *scratchpad; unsigned char *scratchpnt; unsigned char *tmem; -off_t tlen; -off_t unc_memreq = 0; /* for reader */ +fst_off_t tlen; +fst_off_t unc_memreq = 0; /* for reader */ unsigned char *packmem; unsigned int packmemlen; uint32_t *vm4ip; @@ -1733,7 +1739,7 @@ if(tmem) unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen)); int rc = compress2(dmem, &destlen, tmem, tlen, 9); - if((rc == Z_OK) && (((off_t)destlen) < tlen)) + if((rc == Z_OK) && (((fst_off_t)destlen) < tlen)) { fstFwrite(dmem, destlen, 1, xc->handle); } @@ -1781,7 +1787,7 @@ fstWriterFseeko(xc, xc->handle, endpos, SEEK_SET); xc2->section_header_truncpos = endpos; /* cache in case of need to truncate */ if(xc->dump_size_limit) { - if(endpos >= ((off_t)xc->dump_size_limit)) + if(endpos >= ((fst_off_t)xc->dump_size_limit)) { xc2->skip_writing_section_hdr = 1; xc2->size_limit_locked = 1; @@ -1931,7 +1937,7 @@ if(xc) if(xc && !xc->already_in_close && !xc->already_in_flush) { unsigned char *tmem = NULL; - off_t fixup_offs, tlen, hlen; + fst_off_t fixup_offs, tlen, hlen; xc->already_in_close = 1; /* never need to zero this out as it is freed at bottom */ @@ -1991,7 +1997,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) unsigned char *dmem = (unsigned char *)malloc(compressBound(destlen)); int rc = compress2(dmem, &destlen, tmem, tlen, 9); - if((rc != Z_OK) || (((off_t)destlen) > tlen)) + if((rc != Z_OK) || (((fst_off_t)destlen) > tlen)) { destlen = tlen; } @@ -2002,7 +2008,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) fstWriterUint64(xc->handle, tlen); /* uncompressed */ /* compressed len is section length - 24 */ fstWriterUint64(xc->handle, xc->maxhandle); /* maxhandle */ - fstFwrite((((off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle); + fstFwrite((((fst_off_t)destlen) != tlen) ? dmem : tmem, destlen, 1, xc->handle); fflush(xc->handle); fstWriterFseeko(xc, xc->handle, fixup_offs, SEEK_SET); @@ -2018,7 +2024,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) if(xc->num_blackouts) { uint64_t cur_bl = 0; - off_t bpos, eos; + fst_off_t bpos, eos; uint32_t i; fixup_offs = ftello(xc->handle); @@ -2051,7 +2057,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) if(xc->compress_hier) { - off_t hl, eos; + fst_off_t hl, eos; gzFile zhandle; int zfd; int fourpack_duo = 0; @@ -2174,7 +2180,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) if(xc->repack_on_close) { FILE *fp; - off_t offpnt, uclen; + fst_off_t offpnt, uclen; int flen = strlen(xc->filename); char *hf = (char *)calloc(1, flen + 5); @@ -2281,7 +2287,7 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { char s[FST_HDR_DATE_SIZE]; - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); int len = strlen(dat); fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_DATE, SEEK_SET); @@ -2300,7 +2306,7 @@ struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc && vers) { char s[FST_HDR_SIM_VERSION_SIZE]; - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); int len = strlen(vers); fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_SIM_VERSION, SEEK_SET); @@ -2320,7 +2326,7 @@ if(xc) { if(/*(filetype >= FST_FT_MIN) &&*/ (filetype <= FST_FT_MAX)) { - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); xc->filetype = filetype; @@ -2461,7 +2467,7 @@ void fstWriterSetTimescale(void *ctx, int ts) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMESCALE, SEEK_SET); fputc(ts & 255, xc->handle); fflush(xc->handle); @@ -2519,7 +2525,7 @@ void fstWriterSetTimezero(void *ctx, int64_t tim) struct fstWriterContext *xc = (struct fstWriterContext *)ctx; if(xc) { - off_t fpos = ftello(xc->handle); + fst_off_t fpos = ftello(xc->handle); fstWriterFseeko(xc, xc->handle, FST_HDR_OFFS_TIMEZERO, SEEK_SET); fstWriterUint64(xc->handle, (xc->timezero = tim)); fflush(xc->handle); @@ -3361,7 +3367,7 @@ char date[FST_HDR_DATE_SIZE + 1]; int64_t timezero; char *filename, *filename_unpacked; -off_t hier_pos; +fst_off_t hier_pos; uint32_t num_blackouts; uint64_t *blackout_times; @@ -3376,10 +3382,10 @@ uint64_t *rvat_time_table; uint64_t rvat_beg_tim, rvat_end_tim; unsigned char *rvat_frame_data; uint64_t rvat_frame_maxhandle; -off_t *rvat_chain_table; +fst_off_t *rvat_chain_table; uint32_t *rvat_chain_table_lengths; uint64_t rvat_vc_maxhandle; -off_t rvat_vc_start; +fst_off_t rvat_vc_start; uint32_t *rvat_sig_offs; int rvat_packtype; @@ -3418,7 +3424,7 @@ char *fh_nam; }; -int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, off_t offset, int whence) +int fstReaderFseeko(struct fstReaderContext *xc, FILE *stream, fst_off_t offset, int whence) { int rc = fseeko(stream, offset, whence); @@ -3911,11 +3917,11 @@ int pass_status = 1; if(!xc->fh) { - off_t offs_cache = ftello(xc->f); + fst_off_t offs_cache = ftello(xc->f); char *fnam = (char *)malloc(strlen(xc->filename) + 6 + 16 + 32 + 1); unsigned char *mem = (unsigned char *)malloc(FST_GZIO_LEN); - off_t hl, uclen; - off_t clen = 0; + fst_off_t hl, uclen; + fst_off_t clen = 0; gzFile zhandle = NULL; int zfd; int htyp = FST_BL_SKIP; @@ -4535,8 +4541,8 @@ return(1); */ int fstReaderInit(struct fstReaderContext *xc) { -off_t blkpos = 0; -off_t endfile; +fst_off_t blkpos = 0; +fst_off_t endfile; uint64_t seclen; int sectype; uint64_t vc_section_count_actual = 0; @@ -4548,7 +4554,7 @@ sectype = fgetc(xc->f); if(sectype == FST_BL_ZWRAPPER) { FILE *fcomp; - off_t offpnt, uclen; + fst_off_t offpnt, uclen; char gz_membuf[FST_GZIO_LEN]; gzFile zhandle; int zfd; @@ -4981,15 +4987,15 @@ uint64_t *time_table = NULL; uint64_t tsec_nitems; unsigned int secnum = 0; int blocks_skipped = 0; -off_t blkpos = 0; +fst_off_t blkpos = 0; uint64_t seclen, beg_tim; #ifdef FST_DEBUG uint64_t end_tim; #endif uint64_t frame_uclen, frame_clen, frame_maxhandle, vc_maxhandle; -off_t vc_start; -off_t indx_pntr, indx_pos; -off_t *chain_table = NULL; +fst_off_t vc_start; +fst_off_t indx_pntr, indx_pos; +fst_off_t *chain_table = NULL; uint32_t *chain_table_lengths = NULL; unsigned char *chain_cmem; unsigned char *pnt; @@ -5105,7 +5111,7 @@ for(;;) destlen = tsec_uclen; sourcelen = tsec_clen; - fstReaderFseeko(xc, xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); + fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR); if(tsec_uclen != tsec_clen) { @@ -5346,11 +5352,11 @@ for(;;) } free(mu); - fstReaderFseeko(xc, xc->f, -((off_t)frame_clen), SEEK_CUR); + fstReaderFseeko(xc, xc->f, -((fst_off_t)frame_clen), SEEK_CUR); } } - fstReaderFseeko(xc, xc->f, (off_t)frame_clen, SEEK_CUR); /* skip past compressed data */ + fstReaderFseeko(xc, xc->f, (fst_off_t)frame_clen, SEEK_CUR); /* skip past compressed data */ vc_maxhandle = fstReaderVarint64(xc->f); vc_start = ftello(xc->f); /* points to '!' character */ @@ -5380,7 +5386,7 @@ for(;;) free(chain_table_lengths); vc_maxhandle_largest = vc_maxhandle; - chain_table = (off_t *)calloc((vc_maxhandle+1), sizeof(off_t)); + chain_table = (fst_off_t *)calloc((vc_maxhandle+1), sizeof(fst_off_t)); chain_table_lengths = (uint32_t *)calloc((vc_maxhandle+1), sizeof(uint32_t)); } @@ -6001,7 +6007,7 @@ return(buf); char *fstReaderGetValueFromHandleAtTime(void *ctx, uint64_t tim, fstHandle facidx, char *buf) { struct fstReaderContext *xc = (struct fstReaderContext *)ctx; -off_t blkpos = 0, prev_blkpos; +fst_off_t blkpos = 0, prev_blkpos; uint64_t beg_tim, end_tim, beg_tim2, end_tim2; int sectype; unsigned int secnum = 0; @@ -6012,7 +6018,7 @@ uint64_t frame_uclen, frame_clen; #ifdef FST_DEBUG uint64_t mem_required_for_traversal; #endif -off_t indx_pntr, indx_pos; +fst_off_t indx_pntr, indx_pos; long chain_clen; unsigned char *chain_cmem; unsigned char *pnt; @@ -6074,7 +6080,7 @@ for(;;) { if((tim == end_tim) && (tim != xc->end_time)) { - off_t cached_pos = ftello(xc->f); + fst_off_t cached_pos = ftello(xc->f); fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); sectype = fgetc(xc->f); @@ -6136,7 +6142,7 @@ ucdata = (unsigned char *)malloc(tsec_uclen); destlen = tsec_uclen; sourcelen = tsec_clen; -fstReaderFseeko(xc, xc->f, -24 - ((off_t)tsec_clen), SEEK_CUR); +fstReaderFseeko(xc, xc->f, -24 - ((fst_off_t)tsec_clen), SEEK_CUR); if(tsec_uclen != tsec_clen) { cdata = (unsigned char *)malloc(tsec_clen); @@ -6221,7 +6227,7 @@ chain_cmem = (unsigned char *)malloc(chain_clen); fstReaderFseeko(xc, xc->f, indx_pos, SEEK_SET); fstFread(chain_cmem, chain_clen, 1, xc->f); -xc->rvat_chain_table = (off_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(off_t)); +xc->rvat_chain_table = (fst_off_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(fst_off_t)); xc->rvat_chain_table_lengths = (uint32_t *)calloc((xc->rvat_vc_maxhandle+1), sizeof(uint32_t)); pnt = chain_cmem; diff --git a/include/gtkwave/fstapi.h b/include/gtkwave/fstapi.h index e347449ce..e2ca1783a 100644 --- a/include/gtkwave/fstapi.h +++ b/include/gtkwave/fstapi.h @@ -35,7 +35,11 @@ extern "C" { #include #include #include -#include +#if defined(_MSC_VER) + #include "fst_win_unistd.h" +#else + #include +#endif #include #define FST_RDLOAD "FSTLOAD | " diff --git a/include/verilated.cpp b/include/verilated.cpp index 14949b740..aa4bb49c3 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -637,27 +637,80 @@ std::string VL_DECIMAL_NW(int width, WDataInP lwp) VL_MT_SAFE { return output; } -std::string _vl_vsformat_time(char* tmp, double ld, bool left, size_t width) { - // Double may lose precision, but sc_time_stamp has similar limit - std::string suffix = Verilated::threadContextp()->impp()->timeFormatSuffix(); - int userUnits = Verilated::threadContextp()->impp()->timeFormatUnits(); // 0..-15 - int fracDigits = Verilated::threadContextp()->impp()->timeFormatPrecision(); // 0..N - int prec = Verilated::threadContextp()->timeprecision(); // 0..-15 - int shift = prec - userUnits + fracDigits; // 0..-15 - double shiftd = vl_time_multiplier(shift); - double scaled = ld * shiftd; - QData fracDiv = static_cast(vl_time_multiplier(fracDigits)); - QData whole = static_cast(scaled) / fracDiv; - QData fraction = static_cast(scaled) % fracDiv; +template +std::string _vl_vsformat_time(char* tmp, T ld, int timeunit, bool left, size_t width) { + const VerilatedContextImp* const ctxImpp = Verilated::threadContextp()->impp(); + const std::string suffix = ctxImpp->timeFormatSuffix(); + const int userUnits = ctxImpp->timeFormatUnits(); // 0..-15 + const int fracDigits = ctxImpp->timeFormatPrecision(); // 0..N + const int shift = -userUnits + fracDigits + timeunit; // 0..-15 int digits = 0; - if (!fracDigits) { - digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%" VL_PRI64 "u%s", whole, - suffix.c_str()); + if (std::numeric_limits::is_integer) { + constexpr int b = 128; + constexpr int w = VL_WORDS_I(b); + WData tmp0[w], tmp1[w], tmp2[w], tmp3[w]; + + WDataInP shifted = VL_EXTEND_WQ(b, 0, tmp0, static_cast(ld)); + if (shift < 0) { + WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(-shift)); + shifted = VL_DIV_WWW(b, tmp2, shifted, pow10); + } else { + WDataInP pow10 = VL_EXTEND_WQ(b, 0, tmp1, vl_time_pow10(shift)); + shifted = VL_MUL_W(w, tmp2, shifted, pow10); + } + + WDataInP fracDigitsPow10 = VL_EXTEND_WQ(b, 0, tmp3, vl_time_pow10(fracDigits)); + WDataInP integer = VL_DIV_WWW(b, tmp0, shifted, fracDigitsPow10); + WDataInP frac = VL_MODDIV_WWW(b, tmp1, shifted, fracDigitsPow10); + WDataInP max64Bit + = VL_EXTEND_WQ(b, 0, tmp2, std::numeric_limits::max()); // breaks shifted + if (VL_GT_W(w, integer, max64Bit)) { + WDataOutP v = VL_ASSIGN_W(b, tmp3, integer); // breaks fracDigitsPow10 + WData zero[w], ten[w]; + VL_ZERO_W(b, zero); + VL_EXTEND_WI(b, 0, ten, 10); + char buf[128]; // 128B is obviously long enough to represent 128bit integer in decimal + char* ptr = buf + sizeof(buf) - 1; + *ptr = '\0'; + while (VL_GT_W(w, v, zero)) { + --ptr; + WDataInP mod = VL_MODDIV_WWW(b, tmp2, v, ten); // breaks max64Bit + *ptr = "0123456789"[VL_SET_QW(mod)]; + WData divided[w]; + VL_DIV_WWW(b, divided, v, ten); + VL_ASSIGN_W(b, v, divided); + } + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%s%s", ptr, suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%s.%0*" VL_PRI64 "u%s", ptr, + fracDigits, VL_SET_QW(frac), suffix.c_str()); + } + } else { + const vluint64_t integer64 = VL_SET_QW(integer); + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%" VL_PRI64 "u%s", integer64, + suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, + "%" VL_PRI64 "u.%0*" VL_PRI64 "u%s", integer64, fracDigits, + VL_SET_QW(frac), suffix.c_str()); + } + } } else { - digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%" VL_PRI64 "u.%0*" VL_PRI64 "u%s", - whole, fracDigits, fraction, suffix.c_str()); + double shiftd = vl_time_multiplier(shift); + double scaled = ld * shiftd; + const double fracDiv = vl_time_multiplier(fracDigits); + const double whole = scaled / fracDiv; + if (!fracDigits) { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.0f%s", whole, suffix.c_str()); + } else { + digits = VL_SNPRINTF(tmp, VL_VALUE_STRING_MAX_WIDTH, "%.*f%s", fracDigits, whole, + suffix.c_str()); + } } - int needmore = width - digits; + + const int needmore = width - digits; std::string padding; if (needmore > 0) padding.append(needmore, ' '); // Pad with spaces return left ? (tmp + padding) : (padding + tmp); @@ -752,7 +805,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA if (lbits) {} // UNUSED - always 64 if (fmt == '^') { // Realtime if (!widthSet) width = Verilated::threadContextp()->impp()->timeFormatWidth(); - output += _vl_vsformat_time(t_tmp, d, left, width); + const int timeunit = va_arg(ap, int); + output += _vl_vsformat_time(t_tmp, d, timeunit, left, width); } else { std::string fmts(pctp, pos - pctp + 1); VL_SNPRINTF(t_tmp, VL_VALUE_STRING_MAX_WIDTH, fmts.c_str(), d); @@ -851,7 +905,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } case 't': { // Time if (!widthSet) width = Verilated::threadContextp()->impp()->timeFormatWidth(); - output += _vl_vsformat_time(t_tmp, static_cast(ld), left, width); + const int timeunit = va_arg(ap, int); + output += _vl_vsformat_time(t_tmp, ld, timeunit, left, width); break; } case 'b': @@ -2154,6 +2209,30 @@ double vl_time_multiplier(int scale) VL_PURE { return pow10[scale]; } } +vluint64_t vl_time_pow10(int n) { + static const vluint64_t pow10[20] = { + 1ULL, + 10ULL, + 100ULL, + 1000ULL, + 10000ULL, + 100000ULL, + 1000000ULL, + 10000000ULL, + 100000000ULL, + 1000000000ULL, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + }; + return pow10[n]; +} void VL_PRINTTIMESCALE(const char* namep, const char* timeunitp, const VerilatedContext* contextp) VL_MT_SAFE { diff --git a/include/verilated.h b/include/verilated.h index f9a15307c..fcd87fb8d 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -1187,6 +1187,8 @@ inline vluint64_t VerilatedContext::time() const VL_MT_SAFE { // Return time precision as multiplier of time units double vl_time_multiplier(int scale) VL_PURE; +// Return power of 10. e.g. returns 100 if n==2 +vluint64_t vl_time_pow10(int n) VL_PURE; #ifdef VL_DEBUG /// Evaluate statement if Verilated::debug() enabled @@ -1793,7 +1795,7 @@ static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP lwp) VL_M } return owp; } -static void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE { +static inline void VL_NEGATE_INPLACE_W(int words, WDataOutP owp_lwp) VL_MT_SAFE { EData carry = 1; for (int i = 0; i < words; ++i) { EData word = ~owp_lwp[i] + carry; @@ -2487,8 +2489,7 @@ static inline IData VL_SHIFTL_IIW(int obits, int, int rbits, IData lhs, WDataInP } return VL_CLEAN_II(obits, obits, lhs << rwp[0]); } -static inline IData VL_SHIFTL_IIQ(int obits, int lbits, int rbits, IData lhs, - QData rhs) VL_MT_SAFE { +static inline IData VL_SHIFTL_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; return VL_CLEAN_II(obits, obits, lhs << rhs); } @@ -2501,8 +2502,7 @@ static inline QData VL_SHIFTL_QQW(int obits, int, int rbits, QData lhs, WDataInP // Above checks rwp[1]==0 so not needed in below shift return VL_CLEAN_QQ(obits, obits, lhs << (static_cast(rwp[0]))); } -static inline QData VL_SHIFTL_QQQ(int obits, int lbits, int rbits, QData lhs, - QData rhs) VL_MT_SAFE { +static inline QData VL_SHIFTL_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs << rhs); } @@ -2567,11 +2567,11 @@ static inline QData VL_SHIFTR_QQW(int obits, int, int rbits, QData lhs, WDataInP // Above checks rwp[1]==0 so not needed in below shift return VL_CLEAN_QQ(obits, obits, lhs >> (static_cast(rwp[0]))); } -static inline IData VL_SHIFTR_IIQ(int obits, int, int rbits, IData lhs, QData rhs) VL_MT_SAFE { +static inline IData VL_SHIFTR_IIQ(int obits, int, int, IData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_IDATASIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs >> rhs); } -static inline QData VL_SHIFTR_QQQ(int obits, int, int rbits, QData lhs, QData rhs) VL_MT_SAFE { +static inline QData VL_SHIFTR_QQQ(int obits, int, int, QData lhs, QData rhs) VL_MT_SAFE { if (VL_UNLIKELY(rhs >= VL_QUADSIZE)) return 0; return VL_CLEAN_QQ(obits, obits, lhs >> rhs); } @@ -2705,7 +2705,7 @@ static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData static inline IData VL_SEL_IWII(int, int lbits, int, int, WDataInP lwp, IData lsb, IData width) VL_MT_SAFE { int msb = lsb + width - 1; - if (VL_UNLIKELY(msb > lbits)) { + if (VL_UNLIKELY(msb >= lbits)) { return ~0; // Spec says you can go outside the range of a array. Don't coredump if so. } else if (VL_BITWORD_E(msb) == VL_BITWORD_E(static_cast(lsb))) { return VL_BITRSHIFT_W(lwp, lsb); diff --git a/include/verilated.mk.in b/include/verilated.mk.in index e1c8f91ca..bc543442b 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -10,6 +10,7 @@ ###################################################################### PERL = @PERL@ +PYTHON3 = @PYTHON3@ CXX = @CXX@ LINK = @CXX@ AR = ar @@ -35,6 +36,7 @@ CFG_LDLIBS_THREADS = @CFG_LDLIBS_THREADS@ VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage VERILATOR_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer +VERILATOR_CCACHE_REPORT = $(PYTHON3) $(VERILATOR_ROOT)/bin/verilator_ccache_report ###################################################################### # Make checks @@ -202,16 +204,19 @@ else endif # When archiving just objects (.o), use single $(AR) run -# 1. Make .tmp file with list of objects so don't exceed commend line +# 1. Make .verilator_deplist.tmp file with list of objects so don't exceed +# the command line limits when calling $(AR). +# The approach to write the dependency file is compatible with GNU Make 3, +# and can be simplified using the file function once GNU Make 4.x becomes +# the minimum supported version. # When merging objects (.o) and archives (.a) additionally: # 1. Extract object files from .a # 2. Create a new archive from extracted .o and given .o -%.a: +%.a: | %.verilator_deplist.tmp $(info Archive $(AR) -rcs $@ $^) - $(file >$@.tmp) - $(foreach L, $(filter-out %.a,$^), $(file >>$@.tmp, $L)) + $(foreach L, $(filter-out %.a,$^), $(shell echo $L >>$@.verilator_deplist.tmp)) @if test $(words $(filter %.a,$^)) -eq 0; then \ - $(AR) -rcs $@ @$@.tmp; \ + $(AR) -rcs $@ @$@.verilator_deplist.tmp; \ else \ $(RM) -rf $@.tmpdir; \ for archive in $(filter %.a,$^); do \ @@ -220,9 +225,13 @@ endif $(AR) -x ../../$${archive}; \ cd ../..; \ done; \ - $(AR) -rcs $@ @$@.tmp $@.tmpdir/*/*.o; \ + $(AR) -rcs $@ @$@.verilator_deplist.tmp $@.tmpdir/*/*.o; \ fi \ - ; $(RM) -rf $@.tmp $@.tmpdir + ; $(RM) -rf $@.verilator_deplist.tmp $@.tmpdir + +# Truncate the dependency list file used in the %.a target above. +%.verilator_deplist.tmp: + echo "" > $@ $(VM_PREFIX)__ALL.a: $(VK_OBJS) $(VM_HIER_LIBS) @@ -247,6 +256,42 @@ endif #.cpp.o: # $(CXX) $(CXXFLAGS) $(CPPFLAGS) -c -o $@ $< +###################################################################### +### ccache report + +ifneq ($(findstring ccache-report,$(MAKECMDGOALS)),) + ifneq ($(OBJCACHE),ccache) + $(error ccache-report requires OBJCACHE to equal 'ccache') + endif + VK_OTHER_GOALS := $(strip $(subst ccache-report,,$(MAKECMDGOALS))) + ifeq ($(VK_OTHER_GOALS),) + $(error ccache-report must be used with at least one other explicit target) + endif + + # Report ccache behaviour for this invocation of make + VK_CCACHE_LOGDIR := ccache-logs + VK_CCACHE_REPORT := $(VM_PREFIX)__ccache_report.txt + # Remove previous logfiles and report + $(shell rm -rf $(VK_CCACHE_LOGDIR) $(VK_CCACHE_REPORT)) + +$(VK_CCACHE_LOGDIR): + mkdir -p $@ + +$(VK_OBJS): | $(VK_CCACHE_LOGDIR) + +$(VK_OBJS): export CCACHE_LOGFILE=$(VK_CCACHE_LOGDIR)/$@.log + +$(VK_CCACHE_REPORT): $(VK_OBJS) + $(VERILATOR_CCACHE_REPORT) -o $@ $(VK_CCACHE_LOGDIR) + +.PHONY: ccache-report +ccache-report: $(VK_CCACHE_REPORT) + @cat $< + +# ccache-report runs last +ccache-report: $(VK_OTHER_GOALS) +endif + ###################################################################### ### Debugging diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index 3a8e404c5..2426a3e5a 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -152,6 +152,8 @@ public: /// Flush dump void flush() VL_MT_SAFE { m_sptrace.flush(); } /// Write one cycle of dump data + /// Call with the current context's time just after eval'ed, + /// e.g. ->dump(contextp->time()) void dump(vluint64_t timeui) { m_sptrace.dump(timeui); } /// Write one cycle of dump data - backward compatible and to reduce /// conversion warnings. It's better to use a vluint64_t time instead. diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index e89335434..95622b4ad 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -27,6 +27,7 @@ #include "verilated.h" #include +#include #include #include #include diff --git a/include/verilated_imp.h b/include/verilated_imp.h index e1b3d30da..b4d13e0e0 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -245,7 +245,7 @@ public: // But only for verilated*.cpp static vluint32_t randSeedEpoch() VL_MT_SAFE { return s().s_randSeedEpoch; } // METHODS - timeformat - int timeFormatUnits() VL_MT_SAFE { + int timeFormatUnits() const VL_MT_SAFE { if (m_s.m_timeFormatUnits == VerilatedContext::Serialized::UNITS_NONE) return timeprecision(); return m_s.m_timeFormatUnits; @@ -255,7 +255,7 @@ public: // But only for verilated*.cpp void timeFormatPrecision(int value) VL_MT_SAFE { m_s.m_timeFormatPrecision = value; } int timeFormatWidth() const VL_MT_SAFE { return m_s.m_timeFormatWidth; } void timeFormatWidth(int value) VL_MT_SAFE { m_s.m_timeFormatWidth = value; } - std::string timeFormatSuffix() VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) { + std::string timeFormatSuffix() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) { const VerilatedLockGuard lock(m_timeDumpMutex); return m_timeFormatSuffix; } @@ -333,17 +333,20 @@ public: // But only for verilated*.cpp } void fdClose(IData fdi) VL_MT_SAFE_EXCLUDES(m_fdMutex) { const VerilatedLockGuard lock(m_fdMutex); - if ((fdi & (1 << 31)) != 0) { + if (VL_BITISSET_I(fdi, 31)) { // Non-MCD case IData idx = VL_MASK_I(31) & fdi; if (VL_UNLIKELY(idx >= m_fdps.size())) return; + if (VL_UNLIKELY(idx <= 2)) return; // stdout/stdin/stderr if (VL_UNLIKELY(!m_fdps[idx])) return; // Already free std::fclose(m_fdps[idx]); m_fdps[idx] = (FILE*)0; m_fdFree.push_back(idx); } else { // MCD case - for (int i = 0; (fdi != 0) && (i < 31); i++, fdi >>= 1) { + // Starts at 1 to skip stdout + fdi >>= 1; + for (int i = 1; (fdi != 0) && (i < 31); i++, fdi >>= 1) { if (fdi & VL_MASK_I(1)) { std::fclose(m_fdps[i]); m_fdps[i] = nullptr; @@ -375,7 +378,9 @@ private: } } else { // MCD Case - for (size_t i = 0; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) { + if (fdi & 1) fp.push_back(stdout); + fdi >>= 1; + for (size_t i = 1; (fdi != 0) && (i < fp.capacity()); ++i, fdi >>= 1) { if (fdi & VL_MASK_I(1)) fp.push_back(m_fdps[i]); } } diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp index e11ed947d..ccbccde8e 100644 --- a/include/verilated_vcd_c.cpp +++ b/include/verilated_vcd_c.cpp @@ -99,7 +99,6 @@ VerilatedVcd::VerilatedVcd(VerilatedVcdFile* filep) { m_wrBufp = new char[m_wrChunkSize * 8]; m_wrFlushp = m_wrBufp + m_wrChunkSize * 6; m_writep = m_wrBufp; - m_suffixesp = nullptr; } void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) { @@ -114,9 +113,6 @@ void VerilatedVcd::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) { dumpHeader(); - // Get the direct access pointer to the code strings - m_suffixesp = &m_suffixes[0]; // Note: C++11 m_suffixes.data(); - // When using rollover, the first chunk contains the header only. if (m_rolloverMB) openNextImp(true); } @@ -586,8 +582,10 @@ void VerilatedVcd::declTriArray(vluint32_t code, const char* name, bool array, i //============================================================================= // Trace rendering prinitives -void VerilatedVcd::finishLine(vluint32_t code, char* writep) { - const char* const suffixp = m_suffixesp + code * VL_TRACE_SUFFIX_ENTRY_SIZE; +static inline void +VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) VL_ATTR_NO_SANITIZE_ALIGN; + +static inline void VerilatedVcdCCopyAndAppendNewLine(char* writep, const char* suffixp) { // Copy the whole suffix (this avoid having hard to predict branches which // helps a lot). Note: The maximum length of the suffix is // VL_TRACE_MAX_VCD_CODE_SIZE + 2 == 7, but we unroll this here for speed. @@ -605,6 +603,12 @@ void VerilatedVcd::finishLine(vluint32_t code, char* writep) { writep[5] = suffixp[5]; writep[6] = '\n'; // The 6th index is always '\n' if it's relevant, no need to fetch it. #endif +} + +void VerilatedVcd::finishLine(vluint32_t code, char* writep) { + const char* const suffixp = m_suffixes.data() + code * VL_TRACE_SUFFIX_ENTRY_SIZE; + VerilatedVcdCCopyAndAppendNewLine(writep, suffixp); + // Now write back the write pointer incremented by the actual size of the // suffix, which was stored in the last byte of the suffix buffer entry. m_writep = writep + suffixp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1]; diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index f9d07a731..d167d3977 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -80,7 +80,6 @@ private: vluint64_t m_wroteBytes = 0; // Number of bytes written to this file std::vector m_suffixes; // VCD line end string codes + metadata - const char* m_suffixesp; // Pointer to first element of above using NameMap = std::map; NameMap* m_namemapp = nullptr; // List of names for the header @@ -369,6 +368,8 @@ public: /// Flush dump void flush() VL_MT_SAFE { m_sptrace.flush(); } /// Write one cycle of dump data + /// Call with the current context's time just after eval'ed, + /// e.g. ->dump(contextp->time()) void dump(vluint64_t timeui) VL_MT_SAFE { m_sptrace.dump(timeui); } /// Write one cycle of dump data - backward compatible and to reduce /// conversion warnings. It's better to use a vluint64_t time instead. diff --git a/include/verilatedos.h b/include/verilatedos.h index 21cc1447f..06d07d3a6 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -43,6 +43,12 @@ # define VL_ATTR_COLD __attribute__((cold)) # define VL_ATTR_HOT __attribute__((hot)) # define VL_ATTR_NORETURN __attribute__((noreturn)) +// clang and gcc-8.0+ support no_sanitize("string") style attribute +# if defined(__clang__) || (__GNUC__ >= 8) +# define VL_ATTR_NO_SANITIZE_ALIGN __attribute__((no_sanitize("alignment"))) +#else // The entire undefined sanitizer has to be disabled for older gcc +# define VL_ATTR_NO_SANITIZE_ALIGN __attribute__((no_sanitize_undefined)) +#endif # define VL_ATTR_PRINTF(fmtArgNum) __attribute__((format(printf, (fmtArgNum), (fmtArgNum) + 1))) # define VL_ATTR_PURE __attribute__((pure)) # define VL_ATTR_UNUSED __attribute__((unused)) @@ -85,6 +91,9 @@ #ifndef VL_ATTR_NORETURN # define VL_ATTR_NORETURN ///< Attribute that function does not ever return #endif +#ifndef VL_ATTR_NO_SANITIZE_ALIGN +# define VL_ATTR_NO_SANITIZE_ALIGN ///< Attribute that the function contains intended unaligned access +#endif #ifndef VL_ATTR_PRINTF # define VL_ATTR_PRINTF(fmtArgNum) ///< Attribute for function with printf format checking #endif @@ -428,6 +437,7 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type (((nbits) & VL_SIZEBITS_Q) ? ((1ULL << ((nbits) & VL_SIZEBITS_Q)) - 1ULL) : ~0ULL) /// Return mask for EData with 1's where relevant bits are (0=all bits) #define VL_MASK_E(nbits) VL_MASK_I(nbits) + #define VL_EUL(n) VL_UL(n) // Make constant number EData sized #define VL_BITWORD_I(bit) ((bit) / VL_IDATASIZE) ///< Word number for sv DPI vectors diff --git a/src/Makefile.in b/src/Makefile.in index 5dadd276a..2d47f7fc3 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -47,25 +47,25 @@ obj_dbg: .SUFFIXES: -.PHONY: ../bin/verilator_bin ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg +.PHONY: ../bin/verilator_bin$(EXEEXT) ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT) -opt: ../bin/verilator_bin +opt: ../bin/verilator_bin$(EXEEXT) ifeq ($(VERILATOR_NO_OPT_BUILD),1) # Faster laptop development... One build -../bin/verilator_bin: ../bin/verilator_bin_dbg - -cp -p $<$(EXEEXT) $@$(EXEEXT).tmp - -mv -f $@$(EXEEXT).tmp $@$(EXEEXT) +../bin/verilator_bin$(EXEEXT): ../bin/verilator_bin_dbg$(EXEEXT) + -cp -p $< $@.tmp + -mv -f $@.tmp $@ else -../bin/verilator_bin: obj_opt ../bin prefiles +../bin/verilator_bin$(EXEEXT): obj_opt ../bin prefiles $(MAKE) -C obj_opt -j 1 TGT=../$@ -f ../Makefile_obj serial $(MAKE) -C obj_opt TGT=../$@ -f ../Makefile_obj endif -dbg: ../bin/verilator_bin_dbg ../bin/verilator_coverage_bin_dbg -../bin/verilator_bin_dbg: obj_dbg ../bin prefiles +dbg: ../bin/verilator_bin_dbg$(EXEEXT) ../bin/verilator_coverage_bin_dbg$(EXEEXT) +../bin/verilator_bin_dbg$(EXEEXT): obj_dbg ../bin prefiles $(MAKE) -C obj_dbg -j 1 TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj -../bin/verilator_coverage_bin_dbg: obj_dbg ../bin prefiles +../bin/verilator_coverage_bin_dbg$(EXEEXT): obj_dbg ../bin prefiles $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov $(MAKE) -C obj_dbg TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 4562bcd7d..fcd977e14 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -72,7 +72,7 @@ CFG_LIBS = @CFG_LIBS@ #### End of system configuration section. #### VPATH += . $(bldsrc) $(srcdir) -TGT = ../../verilator_bin +TGT = ../../verilator_bin$(EXEEXT) ################# ifeq ($(VL_DEBUG),) @@ -181,6 +181,7 @@ RAW_OBJS = \ V3Depth.o \ V3DepthBlock.o \ V3Descope.o \ + V3DupFinder.o \ V3EmitC.o \ V3EmitCInlines.o \ V3EmitCSyms.o \ @@ -202,7 +203,8 @@ RAW_OBJS = \ V3GraphDfa.o \ V3GraphPathChecker.o \ V3GraphTest.o \ - V3Hashed.o \ + V3Hash.o \ + V3Hasher.o \ V3HierBlock.o \ V3Inline.o \ V3Inst.o \ @@ -221,6 +223,7 @@ RAW_OBJS = \ V3MergeCond.o \ V3Name.o \ V3Number.o \ + V3OptionParser.o \ V3Options.o \ V3Order.o \ V3Os.o \ diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 221bada4f..3e9ee98ad 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -309,16 +309,16 @@ private: } } virtual void visit(AstNodeIf* nodep) { - LatchDetectGraphVertex* parentp = m_graph.currentp(); - LatchDetectGraphVertex* branchp = m_graph.addPathVertex(parentp, "BRANCH", true); - m_graph.addPathVertex(branchp, "IF"); - iterateAndNextNull(nodep->ifsp()); - m_graph.addPathVertex(branchp, "ELSE"); - iterateAndNextNull(nodep->elsesp()); - m_graph.currentp(parentp); + if (!nodep->isBoundsCheck()) { + LatchDetectGraphVertex* parentp = m_graph.currentp(); + LatchDetectGraphVertex* branchp = m_graph.addPathVertex(parentp, "BRANCH", true); + m_graph.addPathVertex(branchp, "IF"); + iterateAndNextNull(nodep->ifsp()); + m_graph.addPathVertex(branchp, "ELSE"); + iterateAndNextNull(nodep->elsesp()); + m_graph.currentp(parentp); + } } - // Empty visitors, speed things up - virtual void visit(AstNodeMath* nodep) {} //-------------------- virtual void visit(AstNode* nodep) { iterateChildren(nodep); } diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 5ee211b09..8b53adf95 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -108,6 +108,7 @@ private: // Like newFireAssert() but omits the asserts-on check AstDisplay* dispp = new AstDisplay(nodep->fileline(), AstDisplayType::DT_ERROR, message, nullptr, nullptr); + dispp->fmtp()->timeunit(m_modp->timeunit()); AstNode* bodysp = dispp; replaceDisplay(dispp, "%%Error"); // Convert to standard DISPLAY format bodysp->addNext(new AstStop(nodep->fileline(), true)); diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 7be1e7a4d..4329c7633 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -970,20 +970,6 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig && (ignNext || sameTreeIter(node1p->m_nextp, node2p->m_nextp, false, gateOnly))); } -//====================================================================== -// Static utilities - -std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) { - return os << std::hex << std::setw(2) << std::setfill('0') << rhs.depth() << "_" - << std::setw(6) << std::setfill('0') << rhs.hshval(); -} - -V3Hash::V3Hash(const string& name) { - uint32_t val = 0; - for (const auto& c : name) val = val * 31 + c; - setBoth(1, val); -} - //====================================================================== // Debugging diff --git a/src/V3Ast.h b/src/V3Ast.h index d1a4709b5..1753b7075 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -1271,6 +1271,8 @@ public: virtual ~AstNVisitor() { doDeletes(); } /// Call visit()s on nodep void iterate(AstNode* nodep); + /// Call visit()s on nodep + void iterateNull(AstNode* nodep); /// Call visit()s on nodep's children void iterateChildren(AstNode* nodep); /// Call visit()s on nodep's children in backp() order @@ -1321,59 +1323,6 @@ inline std::ostream& operator<<(std::ostream& os, const AstNRelinker& rhs) { return os; } -//###################################################################### -// V3Hash -- Node hashing for V3Combine - -class V3Hash final { - // A hash of a tree of nodes, consisting of 8 bits with the number of nodes in the hash - // and 24 bit value hash of relevant information about the node. - // A value of 0 is illegal - uint32_t m_both; - static const uint32_t M24 = ((1 << 24) - 1); - void setBoth(uint32_t depth, uint32_t hshval) { - if (depth == 0) depth = 1; - if (depth > 255) depth = 255; - m_both = (depth << 24) | (hshval & M24); - } - -public: - // METHODS - bool isIllegal() const { return m_both == 0; } - uint32_t fullValue() const { return m_both; } - uint32_t depth() const { return (m_both >> 24) & 255; } - uint32_t hshval() const { return m_both & M24; } - // OPERATORS - bool operator==(const V3Hash& rh) const { return m_both == rh.m_both; } - bool operator!=(const V3Hash& rh) const { return m_both != rh.m_both; } - bool operator<(const V3Hash& rh) const { return m_both < rh.m_both; } - // CONSTRUCTORS - class Illegal {}; // for creator type-overload selection - class FullValue {}; // for creator type-overload selection - explicit V3Hash(Illegal) { m_both = 0; } - // Saving and restoring inside a userp - explicit V3Hash(const VNUser& u) { m_both = u.toInt(); } - V3Hash operator+=(const V3Hash& rh) { - setBoth(depth() + rh.depth(), (hshval() * 31 + rh.hshval())); - return *this; - } - // Creating from raw data (sameHash functions) - V3Hash() { setBoth(1, 0); } - // cppcheck-suppress noExplicitConstructor - V3Hash(uint32_t val) { setBoth(1, val); } - // cppcheck-suppress noExplicitConstructor - V3Hash(const void* vp) { setBoth(1, cvtToHash(vp)); } - // cppcheck-suppress noExplicitConstructor - V3Hash(const string& name); - V3Hash(V3Hash h1, V3Hash h2) { setBoth(1, h1.hshval() * 31 + h2.hshval()); } - V3Hash(V3Hash h1, V3Hash h2, V3Hash h3) { - setBoth(1, (h1.hshval() * 31 + h2.hshval()) * 31 + h3.hshval()); - } - V3Hash(V3Hash h1, V3Hash h2, V3Hash h3, V3Hash h4) { - setBoth(1, ((h1.hshval() * 31 + h2.hshval()) * 31 + h3.hshval()) * 31 + h4.hshval()); - } -}; -std::ostream& operator<<(std::ostream& os, const V3Hash& rhs); - //###################################################################### // Callback base class to determine if node matches some formula @@ -1835,9 +1784,6 @@ public: // statement is unlikely to be taken virtual bool isUnlikely() const { return false; } virtual int instrCount() const { return 0; } - virtual V3Hash sameHash() const { - return V3Hash(V3Hash::Illegal()); // Not a node that supports it - } virtual bool same(const AstNode*) const { return true; } // Iff has a data type; dtype() must be non null virtual bool hasDType() const { return false; } @@ -1912,9 +1858,11 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); } class AstNodeMath VL_NOT_FINAL : public AstNode { // Math -- anything that's part of an expression tree -public: +protected: AstNodeMath(AstType t, FileLine* fl) : AstNode{t, fl} {} + +public: ASTNODE_BASE_FUNCS(NodeMath) // METHODS virtual void dump(std::ostream& str) const override; @@ -1932,9 +1880,11 @@ public: class AstNodeTermop VL_NOT_FINAL : public AstNodeMath { // Terminal operator -- a operator with no "inputs" -public: +protected: AstNodeTermop(AstType t, FileLine* fl) : AstNodeMath{t, fl} {} + +public: ASTNODE_BASE_FUNCS(NodeTermop) // Know no children, and hot function, so skip iterator for speed // See checkTreeIter also that asserts no children @@ -1945,12 +1895,14 @@ public: class AstNodeUniop VL_NOT_FINAL : public AstNodeMath { // Unary math -public: +protected: AstNodeUniop(AstType t, FileLine* fl, AstNode* lhsp) : AstNodeMath{t, fl} { dtypeFrom(lhsp); setOp1p(lhsp); } + +public: ASTNODE_BASE_FUNCS(NodeUniop) AstNode* lhsp() const { return op1p(); } void lhsp(AstNode* nodep) { return setOp1p(nodep); } @@ -1965,18 +1917,19 @@ public: virtual bool signedFlavor() const { return false; } virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; class AstNodeBiop VL_NOT_FINAL : public AstNodeMath { // Binary math -public: +protected: AstNodeBiop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeMath{t, fl} { setOp1p(lhs); setOp2p(rhs); } + +public: ASTNODE_BASE_FUNCS(NodeBiop) // Clone single node, just get same type back. virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; @@ -1997,19 +1950,20 @@ public: virtual bool signedFlavor() const { return false; } virtual bool stringFlavor() const { return false; } // N flavor of nodes with both flavors? virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; class AstNodeTriop VL_NOT_FINAL : public AstNodeMath { // Trinary math -public: +protected: AstNodeTriop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) : AstNodeMath{t, fl} { setOp1p(lhs); setOp2p(rhs); setOp3p(ths); } + +public: ASTNODE_BASE_FUNCS(NodeTriop) AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } @@ -2030,13 +1984,12 @@ public: virtual bool sizeMattersRhs() const = 0; // True if output result depends on rhs size virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { // Quaternary math -public: +protected: AstNodeQuadop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs) : AstNodeMath{t, fl} { setOp1p(lhs); @@ -2044,6 +1997,8 @@ public: setOp3p(ths); setOp4p(fhs); } + +public: ASTNODE_BASE_FUNCS(NodeQuadop) AstNode* lhsp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } @@ -2067,27 +2022,31 @@ public: virtual bool sizeMattersThs() const = 0; // True if output result depends on ths size virtual bool sizeMattersFhs() const = 0; // True if output result depends on ths size virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { // Binary math with commutative properties -public: +protected: AstNodeBiCom(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeBiop{t, fl, lhs, rhs} {} + +public: ASTNODE_BASE_FUNCS(NodeBiCom) }; class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom { // Binary math with commutative & associative properties -public: +protected: AstNodeBiComAsv(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeBiCom{t, fl, lhs, rhs} {} + +public: ASTNODE_BASE_FUNCS(NodeBiComAsv) }; + class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { -public: +protected: AstNodeCond(AstType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) : AstNodeTriop{t, fl, condp, expr1p, expr2p} { if (expr1p) { @@ -2096,6 +2055,8 @@ public: dtypeFrom(expr2p); } } + +public: ASTNODE_BASE_FUNCS(NodeCond) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override; @@ -2124,13 +2085,15 @@ class AstNodeBlock VL_NOT_FINAL : public AstNode { private: string m_name; // Name of block bool m_unnamed; // Originally unnamed (name change does not affect this) -public: +protected: AstNodeBlock(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode{t, fl} , m_name{name} { addNOp1p(stmtsp); m_unnamed = (name == ""); } + +public: ASTNODE_BASE_FUNCS(NodeBlock) virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } // * = Block name @@ -2143,13 +2106,15 @@ public: class AstNodePreSel VL_NOT_FINAL : public AstNode { // Something that becomes an AstSel -public: +protected: AstNodePreSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* rhs, AstNode* ths) : AstNode{t, fl} { setOp1p(fromp); setOp2p(rhs); setNOp3p(ths); } + +public: ASTNODE_BASE_FUNCS(NodePreSel) AstNode* fromp() const { return op1p(); } AstNode* rhsp() const { return op2p(); } @@ -2160,17 +2125,18 @@ public: void thsp(AstNode* nodep) { return setOp3p(nodep); } void attrp(AstAttrOf* nodep) { return setOp4p((AstNode*)nodep); } // METHODS - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; class AstNodeProcedure VL_NOT_FINAL : public AstNode { // IEEE procedure: initial, final, always -public: +protected: AstNodeProcedure(AstType t, FileLine* fl, AstNode* bodysp) : AstNode{t, fl} { addNOp2p(bodysp); } + +public: ASTNODE_BASE_FUNCS(NodeProcedure) // METHODS virtual void dump(std::ostream& str) const override; @@ -2182,10 +2148,12 @@ public: class AstNodeStmt VL_NOT_FINAL : public AstNode { // Statement -- anything that's directly under a function bool m_statement; // Really a statement (e.g. not a function with return) -public: +protected: AstNodeStmt(AstType t, FileLine* fl, bool statement = true) : AstNode{t, fl} , m_statement{statement} {} + +public: ASTNODE_BASE_FUNCS(NodeStmt) // METHODS bool isStatement() const { return m_statement; } // Really a statement @@ -2198,13 +2166,15 @@ public: }; class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { -public: +protected: AstNodeAssign(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeStmt{t, fl} { setOp1p(rhsp); setOp2p(lhsp); dtypeFrom(lhsp); } + +public: ASTNODE_BASE_FUNCS(NodeAssign) // Clone single node, just get same type back. virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) = 0; @@ -2216,14 +2186,13 @@ public: virtual bool hasDType() const override { return true; } virtual bool cleanRhs() const { return true; } virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } virtual string verilogKwd() const override { return "="; } virtual bool brokeLhsMustBeLvalue() const = 0; }; class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { -public: +protected: AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) : AstNodeStmt{t, fl} { @@ -2232,6 +2201,8 @@ public: addNOp3p(incsp); addNOp4p(bodysp); } + +public: ASTNODE_BASE_FUNCS(NodeFor) AstNode* initsp() const { return op1p(); } // op1 = initial statements AstNode* condp() const { return op2p(); } // op2 = condition to continue @@ -2239,20 +2210,23 @@ public: AstNode* bodysp() const { return op4p(); } // op4 = body of loop virtual bool isGateOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; class AstNodeIf VL_NOT_FINAL : public AstNodeStmt { private: VBranchPred m_branchPred; // Branch prediction as taken/untaken? -public: + bool m_isBoundsCheck; // True if this if node was inserted for array bounds checking +protected: AstNodeIf(AstType t, FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) : AstNodeStmt{t, fl} { setOp1p(condp); addNOp2p(ifsp); addNOp3p(elsesp); + isBoundsCheck(false); } + +public: ASTNODE_BASE_FUNCS(NodeIf) AstNode* condp() const { return op1p(); } // op1 = condition AstNode* ifsp() const { return op2p(); } // op2 = list of true statements @@ -2263,19 +2237,22 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isGateDedupable() const override { return true; } virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void branchPred(VBranchPred flag) { m_branchPred = flag; } VBranchPred branchPred() const { return m_branchPred; } + void isBoundsCheck(bool flag) { m_isBoundsCheck = flag; } + bool isBoundsCheck() const { return m_isBoundsCheck; } }; class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { -public: +protected: AstNodeCase(AstType t, FileLine* fl, AstNode* exprp, AstNode* casesp) : AstNodeStmt{t, fl} { setOp1p(exprp); addNOp2p(casesp); } + +public: ASTNODE_BASE_FUNCS(NodeCase) virtual int instrCount() const override { return instrCountBranch(); } AstNode* exprp() const { return op1p(); } // op1 = case condition @@ -2299,7 +2276,7 @@ private: string m_hiernameToUnprot; // Scope converted into name-> for emitting bool m_hierThis = false; // Hiername points to "this" function -public: +protected: AstNodeVarRef(AstType t, FileLine* fl, const string& name, const VAccess& access) : AstNodeMath{t, fl} , m_access{access} @@ -2313,6 +2290,8 @@ public: // May have varp==nullptr this->varp(varp); } + +public: ASTNODE_BASE_FUNCS(NodeVarRef) virtual void dump(std::ostream& str) const override; virtual bool hasDType() const override { return true; } @@ -2346,15 +2325,16 @@ class AstNodeText VL_NOT_FINAL : public AstNode { private: string m_text; -public: +protected: // Node that simply puts text into the output stream AstNodeText(AstType t, FileLine* fl, const string& textp) : AstNode{t, fl} { m_text = textp; // Copy it } + +public: ASTNODE_BASE_FUNCS(NodeText) virtual void dump(std::ostream& str = std::cout) const override; - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool same(const AstNode* samep) const override { const AstNodeText* asamep = static_cast(samep); return text() == asamep->text(); @@ -2375,7 +2355,7 @@ private: // Unique number assigned to each dtype during creation for IEEE matching static int s_uniqueNum; -public: +protected: // CONSTRUCTORS AstNodeDType(AstType t, FileLine* fl) : AstNode{t, fl} { @@ -2383,6 +2363,8 @@ public: m_widthMin = 0; m_generic = false; } + +public: ASTNODE_BASE_FUNCS(NodeDType) // ACCESSORS virtual void dump(std::ostream& str) const override; @@ -2473,16 +2455,21 @@ private: bool m_packed; bool m_isFourstate; MemberNameMap m_members; + const int m_uniqueNum; -public: +protected: AstNodeUOrStructDType(AstType t, FileLine* fl, VSigning numericUnpack) - : AstNodeDType{t, fl} { + : AstNodeDType{t, fl} + , m_uniqueNum{uniqueNumInc()} { // VSigning::NOSIGN overloaded to indicate not packed m_packed = (numericUnpack != VSigning::NOSIGN); m_isFourstate = false; // V3Width computes numeric(VSigning::fromBool(numericUnpack.isSigned())); } + +public: ASTNODE_BASE_FUNCS(NodeUOrStructDType) + int uniqueNum() const { return m_uniqueNum; } virtual const char* broken() const override; virtual void dump(std::ostream& str) const override; virtual bool isCompound() const override { return false; } // Because don't support unpacked @@ -2534,9 +2521,11 @@ class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { private: AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing) AstNode* rangenp() const { return op2p(); } // op2 = Array(s) of variable -public: +protected: AstNodeArrayDType(AstType t, FileLine* fl) : AstNodeDType{t, fl} {} + +public: ASTNODE_BASE_FUNCS(NodeArrayDType) virtual void dump(std::ostream& str) const override; virtual void dumpSmall(std::ostream& str) const override; @@ -2559,9 +2548,6 @@ public: && rangenp()->sameTree(asamep->rangenp()) && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); } - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m_refDTypep), V3Hash(hi()), V3Hash(lo())); - } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } @@ -2594,9 +2580,11 @@ public: class AstNodeSel VL_NOT_FINAL : public AstNodeBiop { // Single bit range extraction, perhaps with non-constant selection or array selection -public: +protected: AstNodeSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* bitp) : AstNodeBiop{t, fl, fromp, bitp} {} + +public: ASTNODE_BASE_FUNCS(NodeSel) AstNode* fromp() const { return op1p(); @@ -2610,11 +2598,13 @@ public: class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() -public: +protected: AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop{t, fl, lhsp, rhsp} { if (lhsp->dtypep()) dtypeSetLogicSized(lhsp->dtypep()->width(), VSigning::UNSIGNED); } + +public: ASTNODE_BASE_FUNCS(NodeStream) }; @@ -2629,28 +2619,19 @@ class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt { string m_hiernameToUnprot; string m_argTypes; -public: +protected: AstNodeCCall(AstType t, FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) : AstNodeStmt{t, fl, true} , m_funcp{funcp} { addNOp2p(argsp); } - // Replacement form for V3Combine - // Note this removes old attachments from the oldp - AstNodeCCall(AstType t, AstNodeCCall* oldp, AstCFunc* funcp) - : AstNodeStmt{t, oldp->fileline(), true} - , m_funcp{funcp} { - m_hiernameToProt = oldp->hiernameToProt(); - m_hiernameToUnprot = oldp->hiernameToUnprot(); - m_argTypes = oldp->argTypes(); - if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext()); - } + +public: ASTNODE_BASE_FUNCS(NodeCCall) virtual void dump(std::ostream& str = std::cout) const override; virtual void cloneRelink() override; virtual const char* broken() const override; virtual int instrCount() const override { return instrCountCall(); } - virtual V3Hash sameHash() const override { return V3Hash(funcp()); } virtual bool same(const AstNode* samep) const override { const AstNodeCCall* asamep = static_cast(samep); return (funcp() == asamep->funcp() && argTypes() == asamep->argTypes()); @@ -2696,7 +2677,7 @@ private: bool m_pureVirtual : 1; // Pure virtual bool m_virtual : 1; // Virtual method in class VLifetime m_lifetime; // Lifetime -public: +protected: AstNodeFTask(AstType t, FileLine* fl, const string& name, AstNode* stmtsp) : AstNode{t, fl} , m_name{name} @@ -2720,6 +2701,8 @@ public: addNOp3p(stmtsp); cname(name); // Might be overridden by dpi import/export } + +public: ASTNODE_BASE_FUNCS(NodeFTask) virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } // * = Var name @@ -2796,7 +2779,7 @@ private: string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out bool m_pli = false; // Pli system call ($name) -public: +protected: AstNodeFTaskRef(AstType t, FileLine* fl, bool statement, AstNode* namep, AstNode* pinsp) : AstNodeStmt{t, fl, statement} { setOp1p(namep); @@ -2807,6 +2790,8 @@ public: , m_name{name} { addNOp3p(pinsp); } + +public: ASTNODE_BASE_FUNCS(NodeFTaskRef) virtual const char* broken() const override; virtual void cloneRelink() override { @@ -2862,7 +2847,7 @@ private: VLifetime m_lifetime; // Lifetime VTimescale m_timeunit; // Global time unit VOptionBool m_unconnectedDrive; // State of `unconnected_drive -public: +protected: AstNodeModule(AstType t, FileLine* fl, const string& name) : AstNode{t, fl} , m_name{name} @@ -2875,6 +2860,8 @@ public: , m_internal{false} , m_recursive{false} , m_recursiveClone{false} {} + +public: ASTNODE_BASE_FUNCS(NodeModule) virtual void dump(std::ostream& str) const override; virtual bool maybePointedTo() const override { return true; } @@ -2922,21 +2909,22 @@ public: class AstNodeRange VL_NOT_FINAL : public AstNode { // A range, sized or unsized -public: +protected: AstNodeRange(AstType t, FileLine* fl) : AstNode{t, fl} {} + +public: ASTNODE_BASE_FUNCS(NodeRange) virtual void dump(std::ostream& str) const override; }; -//###################################################################### - -#include "V3AstNodes__gen.h" - //###################################################################### // Inline AstNVisitor METHODS inline void AstNVisitor::iterate(AstNode* nodep) { nodep->accept(*this); } +inline void AstNVisitor::iterateNull(AstNode* nodep) { + if (VL_LIKELY(nodep)) nodep->accept(*this); +} inline void AstNVisitor::iterateChildren(AstNode* nodep) { nodep->iterateChildren(*this); } inline void AstNVisitor::iterateChildrenBackwards(AstNode* nodep) { nodep->iterateChildrenBackwards(*this); @@ -2955,71 +2943,7 @@ inline AstNode* AstNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) { } //###################################################################### -// Inline ACCESSORS -inline int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } -inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } -inline bool AstNode::width1() const { // V3Const uses to know it can optimize - return dtypep() && dtypep()->width() == 1; -} -inline int AstNode::widthInstrs() const { - return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); -} -inline bool AstNode::isDouble() const { - return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble(); -} -inline bool AstNode::isString() const { - return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); -} -inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } - -inline bool AstNode::isZero() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero()); -} -inline bool AstNode::isNeqZero() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero()); -} -inline bool AstNode::isOne() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne()); -} -inline bool AstNode::isAllOnes() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes()); -} -inline bool AstNode::isAllOnesV() const { - return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV()); -} -inline bool AstNode::sameTree(const AstNode* node2p) const { - return sameTreeIter(this, node2p, true, false); -} -inline bool AstNode::sameGateTree(const AstNode* node2p) const { - return sameTreeIter(this, node2p, true, true); -} - -inline void AstNodeVarRef::varp(AstVar* varp) { - m_varp = varp; - dtypeFrom(varp); -} - -inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } - -inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); } -inline int AstNodeArrayDType::left() const { return rangep()->leftConst(); } -inline int AstNodeArrayDType::right() const { return rangep()->rightConst(); } -inline int AstNodeArrayDType::hi() const { return rangep()->hiConst(); } -inline int AstNodeArrayDType::lo() const { return rangep()->loConst(); } -inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); } -inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange{left(), right()}; } - -inline const char* AstNodeFTaskRef::broken() const { - BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); - BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); - return nullptr; -} - -inline void AstIfaceRefDType::cloneRelink() { - if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep(); - if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep(); - if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); -} +#include "V3AstNodes.h" #endif // Guard diff --git a/src/V3AstInlines.h b/src/V3AstInlines.h new file mode 100644 index 000000000..2ee0ff9ae --- /dev/null +++ b/src/V3AstInlines.h @@ -0,0 +1,93 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Ast node inline functions +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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_V3ASTINLINES_H_ +#define VERILATOR_V3ASTINLINES_H_ + +#ifndef VERILATOR_V3ASTNODES_H_ +#error "Use V3Ast.h as the include" +#include "V3AstNodes.h" // This helps code analysis tools pick up symbols in V3Ast.h and V3AstNodes.h +#endif + +//###################################################################### +// Inline ACCESSORS + +inline int AstNode::width() const { return dtypep() ? dtypep()->width() : 0; } +inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() : 0; } +inline bool AstNode::width1() const { // V3Const uses to know it can optimize + return dtypep() && dtypep()->width() == 1; +} +inline int AstNode::widthInstrs() const { + return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); +} +inline bool AstNode::isDouble() const { + return dtypep() && VN_IS(dtypep(), BasicDType) && VN_CAST(dtypep(), BasicDType)->isDouble(); +} +inline bool AstNode::isString() const { + return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); +} +inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); } + +inline bool AstNode::isZero() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqZero()); +} +inline bool AstNode::isNeqZero() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isNeqZero()); +} +inline bool AstNode::isOne() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->num().isEqOne()); +} +inline bool AstNode::isAllOnes() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnes()); +} +inline bool AstNode::isAllOnesV() const { + return (VN_IS(this, Const) && VN_CAST_CONST(this, Const)->isEqAllOnesV()); +} +inline bool AstNode::sameTree(const AstNode* node2p) const { + return sameTreeIter(this, node2p, true, false); +} +inline bool AstNode::sameGateTree(const AstNode* node2p) const { + return sameTreeIter(this, node2p, true, true); +} + +inline void AstNodeVarRef::varp(AstVar* varp) { + m_varp = varp; + dtypeFrom(varp); +} + +inline bool AstNodeDType::isFourstate() const { return basicp()->isFourstate(); } + +inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); } +inline int AstNodeArrayDType::left() const { return rangep()->leftConst(); } +inline int AstNodeArrayDType::right() const { return rangep()->rightConst(); } +inline int AstNodeArrayDType::hi() const { return rangep()->hiConst(); } +inline int AstNodeArrayDType::lo() const { return rangep()->loConst(); } +inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); } +inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange{left(), right()}; } + +inline const char* AstNodeFTaskRef::broken() const { + BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); + return nullptr; +} + +inline void AstIfaceRefDType::cloneRelink() { + if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep(); + if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep(); + if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep(); +} + +#endif // Guard diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index a5c17b50a..4a6f99d6d 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -25,6 +25,8 @@ #include "V3String.h" #include "V3EmitCBase.h" +#include "V3AstNodes__gen_macros.h" // Generated by 'astgen' + #include #include @@ -214,7 +216,7 @@ AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) { } AstExecGraph::AstExecGraph(FileLine* fileline) - : AstNode{AstType::atExecGraph, fileline} { + : ASTGEN_SUPER_ExecGraph(fileline) { m_depGraphp = new V3Graph; } AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); } diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 0e621df7f..deba4c885 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -19,6 +19,7 @@ #ifndef VERILATOR_V3AST_H_ #error "Use V3Ast.h as the include" +#include "V3Ast.h" // This helps code analysis tools pick up symbols in V3Ast.h #endif //###################################################################### @@ -40,9 +41,9 @@ ASTNODE_NODE_FUNCS_NO_DTOR(name) //###################################################################### -// Macros replaced by 'astgen' +// Macros generated by 'astgen' -#define ASTGEN_SUPER(...) // Roughly: (AstType::at, ...) +#include "V3AstNodes__gen_macros.h" //###################################################################### //=== Ast* : Specific types @@ -66,96 +67,96 @@ private: public: AstConst(FileLine* fl, const V3Number& num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(num) { initWithNumber(); } class WidthedValue {}; // for creator type-overload selection AstConst(FileLine* fl, WidthedValue, int width, uint32_t value) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, width, value) { initWithNumber(); } class DtypedValue {}; // for creator type-overload selection AstConst(FileLine* fl, DtypedValue, AstNodeDType* nodedtypep, uint32_t value) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, nodedtypep->width(), value, nodedtypep->widthSized()) { initWithNumber(); } class StringToParse {}; // for creator type-overload selection AstConst(FileLine* fl, StringToParse, const char* sourcep) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, sourcep) { initWithNumber(); } class VerilogStringLiteral {}; // for creator type-overload selection AstConst(FileLine* fl, VerilogStringLiteral, const string& str) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(V3Number::VerilogStringLiteral(), this, str) { initWithNumber(); } AstConst(FileLine* fl, uint32_t num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 32, num) { dtypeSetLogicUnsized(m_num.width(), 0, VSigning::UNSIGNED); } class Unsized32 {}; // for creator type-overload selection AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 32, num) { m_num.width(32, false); dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::UNSIGNED); } class Signed32 {}; // for creator type-overload selection AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 32, num) { m_num.width(32, true); dtypeSetLogicUnsized(32, m_num.widthMin(), VSigning::SIGNED); } class Unsized64 {}; // for creator type-overload selection AstConst(FileLine* fl, Unsized64, vluint64_t num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 64, 0) { m_num.setQuad(num); dtypeSetLogicSized(64, VSigning::UNSIGNED); } class SizedEData {}; // for creator type-overload selection AstConst(FileLine* fl, SizedEData, vluint64_t num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, VL_EDATASIZE, 0) { m_num.setQuad(num); dtypeSetLogicSized(VL_EDATASIZE, VSigning::UNSIGNED); } class RealDouble {}; // for creator type-overload selection AstConst(FileLine* fl, RealDouble, double num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 64) { m_num.setDouble(num); dtypeSetDouble(); } class String {}; // for creator type-overload selection AstConst(FileLine* fl, String, const string& num) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(V3Number::String(), this, num) { dtypeSetString(); } class BitFalse {}; AstConst(FileLine* fl, BitFalse) // Shorthand const 0, dtype should be a logic of size 1 - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 1, 0) { dtypeSetBit(); } // Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1 class BitTrue {}; AstConst(FileLine* fl, BitTrue, bool on = true) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(this, 1, on) { dtypeSetBit(); } class Null {}; AstConst(FileLine* fl, Null) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Const(fl) , m_num(V3Number::Null{}, this) { dtypeSetBit(); // Events 1 bit, objects 64 bits, so autoExtend=1 and use bit here initWithNumber(); @@ -170,7 +171,6 @@ public: virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(num().toHash()); } virtual bool same(const AstNode* samep) const override { const AstConst* sp = static_cast(samep); return num().isCaseEq(sp->num()); @@ -187,17 +187,17 @@ class AstRange final : public AstNodeRange { // Range specification, for use under variables and cells public: AstRange(FileLine* fl, AstNode* leftp, AstNode* rightp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Range(fl) { setOp2p(leftp); setOp3p(rightp); } AstRange(FileLine* fl, int left, int right) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Range(fl) { setOp2p(new AstConst(fl, left)); setOp3p(new AstConst(fl, right)); } AstRange(FileLine* fl, const VNumRange& range) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Range(fl) { setOp2p(new AstConst(fl, range.left())); setOp3p(new AstConst(fl, range.right())); } @@ -226,7 +226,6 @@ public: bool littleEndian() const { return leftConst() < rightConst(); } virtual void dump(std::ostream& str) const override; virtual string emitC() { V3ERROR_NA_RETURN(""); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -235,13 +234,12 @@ class AstBracketRange final : public AstNodeRange { // unknown until lhsp type is determined public: AstBracketRange(FileLine* fl, AstNode* elementsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BracketRange(fl) { setOp1p(elementsp); } ASTNODE_NODE_FUNCS(BracketRange) virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitVerilog() { V3ERROR_NA_RETURN(""); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // Will be removed in V3Width, which relies on this // being a child not a dtype pointed node @@ -253,11 +251,10 @@ class AstUnsizedRange final : public AstNodeRange { // Unsized range specification, for open arrays public: explicit AstUnsizedRange(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_UnsizedRange(fl) {} ASTNODE_NODE_FUNCS(UnsizedRange) virtual string emitC() { V3ERROR_NA_RETURN(""); } virtual string emitVerilog() { return "[]"; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -265,7 +262,7 @@ class AstGatePin final : public AstNodeMath { // Possibly expand a gate primitive input pin value to match the range of the gate primitive public: AstGatePin(FileLine* fl, AstNode* lhsp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_GatePin(fl) { setOp1p(lhsp); setOp2p(rangep); } @@ -286,7 +283,7 @@ class AstClassPackage final : public AstNodeModule { = nullptr; // Class package this is under (weak pointer, hard link is other way) public: AstClassPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_ClassPackage(fl, name) {} ASTNODE_NODE_FUNCS(ClassPackage) virtual string verilogKwd() const override { return "/*class*/package"; } virtual const char* broken() const override; @@ -307,7 +304,7 @@ class AstClass final : public AstNodeModule { public: AstClass(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_Class(fl, name) {} ASTNODE_NODE_FUNCS(Class) virtual string verilogKwd() const override { return "class"; } virtual bool isHeavy() const override { return true; } @@ -349,7 +346,7 @@ class AstClassExtends final : public AstNode { // during early parse, then moves to dtype public: AstClassExtends(FileLine* fl, AstNode* classOrPkgsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ClassExtends(fl) { setNOp2p(classOrPkgsp); // Only for parser } ASTNODE_NODE_FUNCS(ClassExtends) @@ -374,7 +371,7 @@ private: public: AstParamTypeDType(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ParamTypeDType(fl) , m_varType{type} , m_name{name} { childDTypep(dtp); // Only for parser @@ -423,7 +420,7 @@ private: public: AstTypedef(FileLine* fl, const string& name, AstNode* attrsp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Typedef(fl) , m_name{name} { childDTypep(dtp); // Only for parser addAttrsp(attrsp); @@ -457,7 +454,7 @@ private: public: AstTypedefFwd(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TypedefFwd(fl) , m_name{name} {} ASTNODE_NODE_FUNCS(TypedefFwd) // METHODS @@ -473,27 +470,27 @@ private: string m_name; void* m_containerp; // In what scope is the name unique, so we can know what are duplicate // definitions (arbitrary value) - int m_uniqueNum; + const int m_uniqueNum; public: AstDefImplicitDType(FileLine* fl, const string& name, void* containerp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_DefImplicitDType(fl) , m_name{name} - , m_containerp{containerp} { + , m_containerp{containerp} + , m_uniqueNum{uniqueNumInc()} { childDTypep(dtp); // Only for parser dtypep(nullptr); // V3Width will resolve - m_uniqueNum = uniqueNumInc(); } ASTNODE_NODE_FUNCS(DefImplicitDType) + int uniqueNum() const { return m_uniqueNum; } virtual bool same(const AstNode* samep) const override { const AstDefImplicitDType* sp = static_cast(samep); - return m_uniqueNum == sp->m_uniqueNum; + return uniqueNum() == sp->uniqueNum(); } virtual bool similarDType(AstNodeDType* samep) const override { return type() == samep->type() && same(samep); } - virtual V3Hash sameHash() const override { return V3Hash(m_uniqueNum); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } @@ -525,7 +522,7 @@ private: AstNodeDType* m_keyDTypep; // Keys of this type (after widthing) public: AstAssocArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeDType* keyDtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_AssocArrayDType(fl) { childDTypep(dtp); // Only for parser keyChildDTypep(keyDtp); // Only for parser refDTypep(nullptr); @@ -557,7 +554,6 @@ public: } virtual string prettyDTypeName() const override; virtual void dumpSmall(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } virtual AstNodeDType* getChild2DTypep() const override { return keyChildDTypep(); } virtual bool isHeavy() const override { return true; } @@ -595,7 +591,7 @@ class AstBracketArrayDType final : public AstNodeDType { // Children: DTYPE (the key) public: AstBracketArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* elementsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BracketArrayDType(fl) { setOp1p(dtp); // Only for parser setOp2p(elementsp); // Only for parser } @@ -626,13 +622,13 @@ private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) public: AstDynArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_DynArrayDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); dtypep(nullptr); // V3Width will resolve } AstDynArrayDType(FileLine* fl, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_DynArrayDType(fl) { refDTypep(dtp); dtypep(nullptr); // V3Width will resolve } @@ -657,7 +653,6 @@ public: } virtual string prettyDTypeName() const override; virtual void dumpSmall(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } virtual bool isHeavy() const override { return true; } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable @@ -685,7 +680,7 @@ class AstPackArrayDType final : public AstNodeArrayDType { // Children: RANGE (array bounds) public: AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_PackArrayDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); setOp2p(rangep); @@ -694,7 +689,7 @@ public: widthForce(width, width); } AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_PackArrayDType(fl) { refDTypep(dtp); setOp2p(rangep); dtypep(this); @@ -713,7 +708,7 @@ class AstUnpackArrayDType final : public AstNodeArrayDType { bool m_isCompound = false; // Non-POD subDType, or parent requires compound public: AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UnpackArrayDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); setOp2p(rangep); @@ -723,7 +718,7 @@ public: widthFromSub(subDTypep()); } AstUnpackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UnpackArrayDType(fl) { refDTypep(dtp); setOp2p(rangep); dtypep(this); @@ -750,7 +745,7 @@ private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) public: AstUnsizedArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UnsizedArrayDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); dtypep(nullptr); // V3Width will resolve @@ -775,7 +770,6 @@ public: && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } virtual void dumpSmall(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } @@ -810,24 +804,24 @@ private: // See also in AstNodeDType: m_width, m_widthMin, m_numeric(issigned) public: AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, const VSigning& signst = VSigning::NOSIGN) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(kwd, signst, 0, -1, nullptr); } AstBasicDType(FileLine* fl, VFlagLogicPacked, int wantwidth) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(AstBasicDTypeKwd::LOGIC, VSigning::NOSIGN, wantwidth, -1, nullptr); } AstBasicDType(FileLine* fl, VFlagBitPacked, int wantwidth) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(AstBasicDTypeKwd::BIT, VSigning::NOSIGN, wantwidth, -1, nullptr); } AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSigning numer, int wantwidth, int widthmin) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(kwd, numer, wantwidth, widthmin, nullptr); } AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, VSigning numer, VNumRange range, int widthmin) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_BasicDType(fl) { init(kwd, numer, range.elements(), widthmin, nullptr); m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be } @@ -873,9 +867,6 @@ private: public: ASTNODE_NODE_FUNCS(BasicDType) virtual void dump(std::ostream& str) const override; - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.hi())); - } // width/widthMin/numeric compared elsewhere virtual bool same(const AstNode* samep) const override { const AstBasicDType* sp = static_cast(samep); @@ -935,6 +926,7 @@ public: const VNumRange& nrange() const { return m.m_nrange; } int hi() const { return (rangep() ? rangep()->hiConst() : m.m_nrange.hi()); } int lo() const { return (rangep() ? rangep()->loConst() : m.m_nrange.lo()); } + int elements() const { return (rangep() ? rangep()->elementsConst() : m.m_nrange.elements()); } int left() const { return littleEndian() ? lo() : hi(); } // How to show a declaration int right() const { return littleEndian() ? hi() : lo(); } bool littleEndian() const { @@ -960,7 +952,7 @@ private: AstNodeDType* m_refDTypep; // Inherit from this base data type public: AstConstDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ConstDType(fl) { childDTypep(dtp); // Only for parser refDTypep(nullptr); // V3Width will resolve dtypep(nullptr); // V3Width will resolve @@ -982,9 +974,6 @@ public: virtual bool similarDType(AstNodeDType* samep) const override { return skipRefp()->similarDType(samep->skipRefp()); } - virtual V3Hash sameHash() const override { - return V3Hash(m_refDTypep); - } // node's type() included elsewhere virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } // op1 = Range of variable AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } @@ -1016,7 +1005,7 @@ private: AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy public: AstClassRefDType(FileLine* fl, AstClass* classp, AstNode* paramsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ClassRefDType(fl) , m_classp{classp} { dtypep(this); addNOp4p(paramsp); @@ -1037,9 +1026,6 @@ public: virtual bool similarDType(AstNodeDType* samep) const override { return this == samep || (type() == samep->type() && same(samep)); } - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m_classp), V3Hash(m_classOrPackagep)); - } virtual void dump(std::ostream& str = std::cout) const override; virtual void dumpSmall(std::ostream& str) const override; virtual string name() const override { return classp() ? classp()->name() : ""; } @@ -1072,14 +1058,14 @@ private: AstModport* m_modportp = nullptr; // nullptr = unlinked or no modport public: AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_IfaceRefDType(fl) , m_modportFileline{nullptr} , m_cellName{cellName} , m_ifaceName{ifaceName} , m_modportName{""} {} AstIfaceRefDType(FileLine* fl, FileLine* modportFl, const string& cellName, const string& ifaceName, const string& modport) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_IfaceRefDType(fl) , m_modportFileline{modportFl} , m_cellName{cellName} , m_ifaceName{ifaceName} @@ -1095,7 +1081,6 @@ public: virtual AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; } virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual V3Hash sameHash() const override { return V3Hash(m_cellp); } virtual int widthAlignBytes() const override { return 1; } virtual int widthTotalBytes() const override { return 1; } FileLine* modportFileline() const { return m_modportFileline; } @@ -1123,14 +1108,14 @@ private: AstNodeDType* m_refDTypep; // Elements of this type (after widthing) public: AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* boundp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_QueueDType(fl) { setNOp2p(boundp); childDTypep(dtp); // Only for parser refDTypep(nullptr); dtypep(nullptr); // V3Width will resolve } AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_QueueDType(fl) { setNOp2p(boundp); refDTypep(dtp); dtypep(dtp); @@ -1155,7 +1140,6 @@ public: && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } virtual void dumpSmall(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } virtual string prettyDTypeName() const override; virtual bool isHeavy() const override { return true; } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } @@ -1198,17 +1182,17 @@ private: AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy public: AstRefDType(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_RefDType(fl) , m_name{name} {} AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstNode* paramsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_RefDType(fl) , m_name{name} { setNOp3p(classOrPackagep); addNOp4p(paramsp); } class FlagTypeOfExpr {}; // type(expr) for parser only AstRefDType(FileLine* fl, FlagTypeOfExpr, AstNode* typeofp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_RefDType(fl) { setOp2p(typeofp); } ASTNODE_NODE_FUNCS(RefDType) @@ -1230,9 +1214,6 @@ public: virtual bool similarDType(AstNodeDType* samep) const override { return skipRefp()->similarDType(samep->skipRefp()); } - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m_typedefp), V3Hash(m_classOrPackagep)); - } virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } virtual string prettyDTypeName() const override { @@ -1296,7 +1277,7 @@ class AstStructDType final : public AstNodeUOrStructDType { public: // VSigning below is mispurposed to indicate if packed or not AstStructDType(FileLine* fl, VSigning numericUnpack) - : ASTGEN_SUPER(fl, numericUnpack) {} + : ASTGEN_SUPER_StructDType(fl, numericUnpack) {} ASTNODE_NODE_FUNCS(StructDType) virtual string verilogKwd() const override { return "struct"; } }; @@ -1306,7 +1287,7 @@ public: // UNSUP: bool isTagged; // VSigning below is mispurposed to indicate if packed or not AstUnionDType(FileLine* fl, VSigning numericUnpack) - : ASTGEN_SUPER(fl, numericUnpack) {} + : ASTGEN_SUPER_UnionDType(fl, numericUnpack) {} ASTNODE_NODE_FUNCS(UnionDType) virtual string verilogKwd() const override { return "union"; } }; @@ -1322,14 +1303,14 @@ private: // UNSUP: int m_randType; // Randomization type (IEEE) public: AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MemberDType(fl) , m_name{name} { childDTypep(dtp); // Only for parser dtypep(nullptr); // V3Width will resolve refDTypep(nullptr); } AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MemberDType(fl) , m_name{name} { UASSERT(dtp, "AstMember created with no dtype"); refDTypep(dtp); @@ -1382,7 +1363,7 @@ class AstVoidDType final : public AstNodeDType { // For e.g. a function returning void public: explicit AstVoidDType(FileLine* fl) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_VoidDType(fl) { dtypep(this); } ASTNODE_NODE_FUNCS(VoidDType) @@ -1402,7 +1383,6 @@ public: virtual AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; } virtual int widthAlignBytes() const override { return 1; } virtual int widthTotalBytes() const override { return 1; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool isCompound() const override { return false; } }; @@ -1413,7 +1393,7 @@ private: public: // Parents: ENUM AstEnumItem(FileLine* fl, const string& name, AstNode* rangep, AstNode* initp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_EnumItem(fl) , m_name{name} { addNOp1p(rangep); addNOp2p(initp); @@ -1435,7 +1415,7 @@ private: AstNodeModule* m_classOrPackagep; // Package hierarchy public: AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_EnumItemRef(fl) , m_itemp{itemp} , m_classOrPackagep{classOrPackagep} { dtypeFrom(m_itemp); @@ -1469,17 +1449,17 @@ class AstEnumDType final : public AstNodeDType { private: string m_name; // Name from upper typedef, if any AstNodeDType* m_refDTypep; // Elements are of this type after V3Width - int m_uniqueNum; + const int m_uniqueNum; public: AstEnumDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* itemsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_EnumDType(fl) + , m_uniqueNum{uniqueNumInc()} { childDTypep(dtp); // Only for parser refDTypep(nullptr); addNOp2p(itemsp); dtypep(nullptr); // V3Width will resolve widthFromSub(subDTypep()); - m_uniqueNum = uniqueNumInc(); } ASTNODE_NODE_FUNCS(EnumDType) virtual const char* broken() const override { @@ -1490,12 +1470,12 @@ public: virtual void cloneRelink() override { if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep(); } + int uniqueNum() const { return m_uniqueNum; } virtual bool same(const AstNode* samep) const override { const AstEnumDType* sp = static_cast(samep); - return m_uniqueNum == sp->m_uniqueNum; + return uniqueNum() == sp->uniqueNum(); } virtual bool similarDType(AstNodeDType* samep) const override { return this == samep; } - virtual V3Hash sameHash() const override { return V3Hash(m_uniqueNum); } virtual AstNodeDType* getChildDTypep() const override { return childDTypep(); } AstNodeDType* childDTypep() const { return VN_CAST(op1p(), NodeDType); } // op1 = Data type void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } @@ -1534,7 +1514,7 @@ class AstParseTypeDType final : public AstNodeDType { // e.g. the data type is a container of any data type public: explicit AstParseTypeDType(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_ParseTypeDType(fl) {} ASTNODE_NODE_FUNCS(ParseTypeDType) AstNodeDType* dtypep() const { return nullptr; } // METHODS @@ -1568,11 +1548,11 @@ private: public: AstArraySel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER(fl, fromp, bitp) { + : ASTGEN_SUPER_ArraySel(fl, fromp, bitp) { init(fromp); } AstArraySel(FileLine* fl, AstNode* fromp, int bit) - : ASTGEN_SUPER(fl, fromp, new AstConst(fl, bit)) { + : ASTGEN_SUPER_ArraySel(fl, fromp, new AstConst(fl, bit)) { init(fromp); } ASTNODE_NODE_FUNCS(ArraySel) @@ -1593,7 +1573,6 @@ public: return true; } // esp for V3Const::ifSameAssign virtual bool isPredictOptimizable() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual int instrCount() const override { return widthInstrs(); } // Special operators @@ -1614,7 +1593,7 @@ private: public: AstAssocSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER(fl, fromp, bitp) { + : ASTGEN_SUPER_AssocSel(fl, fromp, bitp) { init(fromp); } ASTNODE_NODE_FUNCS(AssocSel) @@ -1635,7 +1614,6 @@ public: return true; } // esp for V3Const::ifSameAssign virtual bool isPredictOptimizable() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual int instrCount() const override { return widthInstrs(); } }; @@ -1644,7 +1622,7 @@ class AstWordSel final : public AstNodeSel { // Select a single word from a multi-word wide value public: AstWordSel(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER(fl, fromp, bitp) { + : ASTGEN_SUPER_WordSel(fl, fromp, bitp) { dtypeSetUInt32(); // Always used on WData arrays so returns edata size } ASTNODE_NODE_FUNCS(WordSel) @@ -1663,7 +1641,6 @@ public: virtual bool cleanRhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -1672,12 +1649,11 @@ class AstSelLoopVars final : public AstNode { // Unlike normal selects elements is a list public: AstSelLoopVars(FileLine* fl, AstNode* fromp, AstNode* elementsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SelLoopVars(fl) { setOp1p(fromp); addNOp2p(elementsp); } ASTNODE_NODE_FUNCS(SelLoopVars) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool maybePointedTo() const override { return false; } AstNode* fromp() const { return op1p(); } @@ -1688,7 +1664,7 @@ class AstSelExtract final : public AstNodePreSel { // Range extraction, gets replaced with AstSel public: AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) - : ASTGEN_SUPER(fl, fromp, msbp, lsbp) {} + : ASTGEN_SUPER_SelExtract(fl, fromp, msbp, lsbp) {} ASTNODE_NODE_FUNCS(SelExtract) AstNode* leftp() const { return rhsp(); } AstNode* rightp() const { return thsp(); } @@ -1699,7 +1675,7 @@ class AstSelBit final : public AstNodePreSel { // Gets replaced during link with AstArraySel or AstSel public: AstSelBit(FileLine* fl, AstNode* fromp, AstNode* bitp) - : ASTGEN_SUPER(fl, fromp, bitp, nullptr) { + : ASTGEN_SUPER_SelBit(fl, fromp, bitp, nullptr) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, "not coded to create after dtypes resolved"); } @@ -1712,7 +1688,7 @@ class AstSelPlus final : public AstNodePreSel { // Gets replaced during link with AstSel public: AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER(fl, fromp, bitp, widthp) {} + : ASTGEN_SUPER_SelPlus(fl, fromp, bitp, widthp) {} ASTNODE_NODE_FUNCS(SelPlus) AstNode* bitp() const { return rhsp(); } AstNode* widthp() const { return thsp(); } @@ -1723,7 +1699,7 @@ class AstSelMinus final : public AstNodePreSel { // Gets replaced during link with AstSel public: AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp) - : ASTGEN_SUPER(fl, fromp, bitp, widthp) {} + : ASTGEN_SUPER_SelMinus(fl, fromp, bitp, widthp) {} ASTNODE_NODE_FUNCS(SelMinus) AstNode* bitp() const { return rhsp(); } AstNode* widthp() const { return thsp(); } @@ -1740,14 +1716,14 @@ private: int m_declElWidth; // If a packed array, the number of bits per element public: AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp) - : ASTGEN_SUPER(fl, fromp, lsbp, widthp) + : ASTGEN_SUPER_Sel(fl, fromp, lsbp, widthp) , m_declElWidth{1} { if (VN_IS(widthp, Const)) { dtypeSetLogicSized(VN_CAST(widthp, Const)->toUInt(), VSigning::UNSIGNED); } } AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth) - : ASTGEN_SUPER(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) + : ASTGEN_SUPER_Sel(fl, fromp, new AstConst(fl, lsb), new AstConst(fl, bitwidth)) , m_declElWidth{1} { dtypeSetLogicSized(bitwidth, VSigning::UNSIGNED); } @@ -1769,7 +1745,6 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } virtual bool sizeMattersThs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } virtual int instrCount() const override { return widthInstrs() * (VN_CAST(lsbp(), Const) ? 3 : 10); @@ -1797,8 +1772,8 @@ private: VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid public: AstSliceSel(FileLine* fl, AstNode* fromp, const VNumRange& declRange) - : ASTGEN_SUPER(fl, fromp, new AstConst(fl, declRange.lo()), - new AstConst(fl, declRange.elements())) + : ASTGEN_SUPER_SliceSel(fl, fromp, new AstConst(fl, declRange.lo()), + new AstConst(fl, declRange.elements())) , m_declRange{declRange} {} ASTNODE_NODE_FUNCS(SliceSel) virtual void dump(std::ostream& str) const override; @@ -1815,7 +1790,6 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } virtual bool sizeMattersThs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } virtual int instrCount() const override { return 10; } // Removed before matters AstNode* fromp() const { @@ -1835,12 +1809,12 @@ class AstMethodCall final : public AstNodeFTaskRef { public: AstMethodCall(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, name, pinsp) { + : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { setOp2p(fromp); dtypep(nullptr); // V3Width will resolve } AstMethodCall(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, name, pinsp) { + : ASTGEN_SUPER_MethodCall(fl, false, name, pinsp) { setOp2p(fromp); } ASTNODE_NODE_FUNCS(MethodCall) @@ -1871,14 +1845,14 @@ private: public: AstCMethodHard(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false) + : ASTGEN_SUPER_CMethodHard(fl, false) , m_name{name} { setOp1p(fromp); dtypep(nullptr); // V3Width will resolve addNOp2p(pinsp); } AstCMethodHard(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false) + : ASTGEN_SUPER_CMethodHard(fl, false) , m_name{name} { setOp1p(fromp); addNOp2p(pinsp); @@ -1887,7 +1861,6 @@ public: virtual string name() const override { return m_name; } // * = Var name virtual bool hasDType() const override { return true; } virtual void name(const string& name) override { m_name = name; } - virtual V3Hash sameHash() const override { return V3Hash(m_name); } virtual bool same(const AstNode* samep) const override { const AstCMethodHard* asamep = static_cast(samep); return (m_name == asamep->m_name); @@ -1998,7 +1971,7 @@ private: public: AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -2012,7 +1985,7 @@ public: } } AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -2026,7 +1999,7 @@ public: } } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -2035,7 +2008,7 @@ public: m_declKwd = AstBasicDTypeKwd::LOGIC; } AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -2044,7 +2017,7 @@ public: m_declKwd = AstBasicDTypeKwd::BIT; } AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Var(fl) , m_name{name} , m_origName{name} { init(); @@ -2265,14 +2238,13 @@ private: string m_path; // Dotted cellname to set parameter of public: AstDefParam(FileLine* fl, const string& path, const string& name, AstNode* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_DefParam(fl) { setOp1p(rhsp); m_name = name; m_path = path; } virtual string name() const override { return m_name; } // * = Scope name ASTNODE_NODE_FUNCS(DefParam) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } AstNode* rhsp() const { return op1p(); } // op1 = Assign from string path() const { return m_path; } @@ -2283,7 +2255,7 @@ class AstImplicit final : public AstNode { // Parents: MODULE public: AstImplicit(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Implicit(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(Implicit) @@ -2303,7 +2275,7 @@ private: public: AstScope(FileLine* fl, AstNodeModule* modp, const string& name, AstScope* aboveScopep, AstCell* aboveCellp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Scope(fl) , m_name{name} , m_aboveScopep{aboveScopep} , m_aboveCellp{aboveCellp} @@ -2336,7 +2308,7 @@ class AstTopScope final : public AstNode { // Children: SCOPEs public: AstTopScope(FileLine* fl, AstScope* ascopep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_TopScope(fl) { addNOp2p(ascopep); } ASTNODE_NODE_FUNCS(TopScope) @@ -2358,7 +2330,7 @@ private: bool m_trace : 1; // Tracing is turned on for this scope public: AstVarScope(FileLine* fl, AstScope* scopep, AstVar* varp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_VarScope(fl) , m_scopep{scopep} , m_varp{varp} { m_circular = false; @@ -2397,21 +2369,18 @@ class AstVarRef final : public AstNodeVarRef { // A reference to a variable (lvalue or rvalue) public: AstVarRef(FileLine* fl, const string& name, const VAccess& access) - : ASTGEN_SUPER(fl, name, nullptr, access) {} + : ASTGEN_SUPER_VarRef(fl, name, nullptr, access) {} // This form only allowed post-link because output/wire compression may // lead to deletion of AstVar's AstVarRef(FileLine* fl, AstVar* varp, const VAccess& access) - : ASTGEN_SUPER(fl, varp->name(), varp, access) {} + : ASTGEN_SUPER_VarRef(fl, varp->name(), varp, access) {} // This form only allowed post-link (see above) AstVarRef(FileLine* fl, AstVarScope* varscp, const VAccess& access) - : ASTGEN_SUPER(fl, varscp->varp()->name(), varscp->varp(), access) { + : ASTGEN_SUPER_VarRef(fl, varscp->varp()->name(), varscp->varp(), access) { varScopep(varscp); } ASTNODE_NODE_FUNCS(VarRef) virtual void dump(std::ostream& str) const override; - virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(varp()->name()), V3Hash(hiernameToProt())); - } virtual bool same(const AstNode* samep) const override { return same(static_cast(samep)); } @@ -2450,10 +2419,10 @@ private: string m_inlinedDots; // Dotted hierarchy flattened out public: AstVarXRef(FileLine* fl, const string& name, const string& dotted, const VAccess& access) - : ASTGEN_SUPER(fl, name, nullptr, access) + : ASTGEN_SUPER_VarXRef(fl, name, nullptr, access) , m_dotted{dotted} {} AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const VAccess& access) - : ASTGEN_SUPER(fl, varp->name(), varp, access) + : ASTGEN_SUPER_VarXRef(fl, varp->name(), varp, access) , m_dotted{dotted} { dtypeFrom(varp); } @@ -2468,7 +2437,6 @@ public: virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(V3Hash(varp()), V3Hash(dotted())); } virtual bool same(const AstNode* samep) const override { const AstVarXRef* asamep = static_cast(samep); return (hiernameToProt() == asamep->hiernameToProt() @@ -2488,13 +2456,13 @@ private: bool m_svImplicit = false; // Pin is SystemVerilog .name'ed public: AstPin(FileLine* fl, int pinNum, const string& name, AstNode* exprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Pin(fl) , m_pinNum{pinNum} , m_name{name} { setNOp1p(exprp); } AstPin(FileLine* fl, int pinNum, AstVarRef* varname, AstNode* exprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Pin(fl) , m_pinNum{pinNum} , m_name{varname->name()} { setNOp1p(exprp); @@ -2537,14 +2505,13 @@ private: string m_name; // Pin name, or "" for number based interconnect public: AstArg(FileLine* fl, const string& name, AstNode* exprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Arg(fl) , m_name{name} { setNOp1p(exprp); } ASTNODE_NODE_FUNCS(Arg) virtual string name() const override { return m_name; } // * = Pin name, ""=go by number virtual void name(const string& name) override { m_name = name; } - virtual V3Hash sameHash() const override { return V3Hash(); } void exprp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expression connected to pin, nullptr if unconnected AstNode* exprp() const { return op1p(); } @@ -2557,7 +2524,7 @@ private: bool m_isProgram; // Module represents a program public: AstModule(FileLine* fl, const string& name, bool program = false) - : ASTGEN_SUPER(fl, name) + : ASTGEN_SUPER_Module(fl, name) , m_isProgram{program} {} ASTNODE_NODE_FUNCS(Module) virtual string verilogKwd() const override { return m_isProgram ? "program" : "module"; } @@ -2568,7 +2535,7 @@ class AstNotFoundModule final : public AstNodeModule { // A missing module declaration public: AstNotFoundModule(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_NotFoundModule(fl, name) {} ASTNODE_NODE_FUNCS(NotFoundModule) virtual string verilogKwd() const override { return "/*not-found-*/ module"; } virtual bool timescaleMatters() const override { return false; } @@ -2578,7 +2545,7 @@ class AstPackage final : public AstNodeModule { // A package declaration public: AstPackage(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_Package(fl, name) {} ASTNODE_NODE_FUNCS(Package) virtual string verilogKwd() const override { return "package"; } virtual bool timescaleMatters() const override { return !isDollarUnit(); } @@ -2590,7 +2557,7 @@ class AstPrimitive final : public AstNodeModule { // A primitive declaration public: AstPrimitive(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_Primitive(fl, name) {} ASTNODE_NODE_FUNCS(Primitive) virtual string verilogKwd() const override { return "primitive"; } virtual bool timescaleMatters() const override { return false; } @@ -2601,7 +2568,7 @@ class AstPackageExportStarStar final : public AstNode { public: // cppcheck-suppress noExplicitConstructor AstPackageExportStarStar(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_PackageExportStarStar(fl) {} ASTNODE_NODE_FUNCS(PackageExportStarStar) }; @@ -2612,7 +2579,7 @@ private: AstPackage* m_packagep; // Package hierarchy public: AstPackageExport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_PackageExport(fl) , m_name{name} , m_packagep{packagep} {} ASTNODE_NODE_FUNCS(PackageExport) @@ -2636,7 +2603,7 @@ private: AstPackage* m_packagep; // Package hierarchy public: AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_PackageImport(fl) , m_name{name} , m_packagep{packagep} {} ASTNODE_NODE_FUNCS(PackageImport) @@ -2657,7 +2624,7 @@ class AstIface final : public AstNodeModule { // A module declaration public: AstIface(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_Iface(fl, name) {} ASTNODE_NODE_FUNCS(Iface) // Interfaces have `timescale applicability but lots of code seems to // get false warnings if we enable this @@ -2673,13 +2640,13 @@ private: AstVar* m_varp = nullptr; // Post link, variable within class that is target of selection public: AstMemberSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MemberSel(fl) , m_name{name} { setOp1p(fromp); dtypep(nullptr); // V3Width will resolve } AstMemberSel(FileLine* fl, AstNode* fromp, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MemberSel(fl) , m_name{dtp->name()} { setOp1p(fromp); dtypep(dtp); @@ -2694,7 +2661,6 @@ public: } virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } - virtual V3Hash sameHash() const override { return V3Hash(m_name); } virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return false; } @@ -2721,7 +2687,7 @@ private: AstNodeFTask* m_ftaskp = nullptr; // Link to the function public: AstModportFTaskRef(FileLine* fl, const string& name, bool isExport) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ModportFTaskRef(fl) , m_name{name} , m_export{isExport} {} ASTNODE_NODE_FUNCS(ModportFTaskRef) @@ -2750,7 +2716,7 @@ private: AstVar* m_varp = nullptr; // Link to the actual Var public: AstModportVarRef(FileLine* fl, const string& name, VDirection::en direction) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ModportVarRef(fl) , m_name{name} , m_direction{direction} {} ASTNODE_NODE_FUNCS(ModportVarRef) @@ -2775,7 +2741,7 @@ private: string m_name; // Name of the modport public: AstModport(FileLine* fl, const string& name, AstNode* varsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Modport(fl) , m_name{name} { addNOp1p(varsp); } @@ -2791,7 +2757,7 @@ private: string m_name; // Name of the reference public: AstIntfRef(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_IntfRef(fl) , m_name{name} {} virtual string name() const override { return m_name; } ASTNODE_NODE_FUNCS(IntfRef) @@ -2811,7 +2777,7 @@ private: public: AstCell(FileLine* fl, FileLine* mfl, const string& instName, const string& modName, AstPin* pinsp, AstPin* paramsp, AstRange* rangep) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Cell(fl) , m_modNameFileline{mfl} , m_name{instName} , m_origName{instName} @@ -2873,7 +2839,7 @@ private: public: AstCellInline(FileLine* fl, const string& name, const string& origModName, const VTimescale& timeunit) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CellInline(fl) , m_name{name} , m_origModName{origModName} , m_timeunit{timeunit} {} @@ -2899,7 +2865,7 @@ private: string m_name; // Cell name public: AstCellRef(FileLine* fl, const string& name, AstNode* cellp, AstNode* exprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CellRef(fl) , m_name{name} { addNOp1p(cellp); addNOp2p(exprp); @@ -2917,7 +2883,7 @@ private: string m_name; // Array name public: AstCellArrayRef(FileLine* fl, const string& name, AstNode* selectExprp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CellArrayRef(fl) , m_name{name} { addNOp1p(selectExprp); } @@ -2933,7 +2899,7 @@ private: string m_name; // Var name public: AstUnlinkedRef(FileLine* fl, AstNode* refp, const string& name, AstNode* crp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_UnlinkedRef(fl) , m_name{name} { addNOp1p(refp); addNOp2p(crp); @@ -2952,7 +2918,7 @@ private: string m_name; // Binding to name public: AstBind(FileLine* fl, const string& name, AstNode* cellsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Bind(fl) , m_name{name} { UASSERT_OBJ(VN_IS(cellsp, Cell), cellsp, "Only instances allowed to be bound"); addNOp1p(cellsp); @@ -2971,7 +2937,7 @@ private: string m_name; // Name of pin public: AstPort(FileLine* fl, int pinnum, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Port(fl) , m_pinNum{pinnum} , m_name{name} {} ASTNODE_NODE_FUNCS(Port) @@ -2995,7 +2961,7 @@ private: public: AstParseRef(FileLine* fl, VParseRefExp expect, const string& name, AstNode* lhsp = nullptr, AstNodeFTaskRef* ftaskrefp = nullptr) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ParseRef(fl) , m_expect{expect} , m_name{name} { setNOp1p(lhsp); @@ -3004,7 +2970,6 @@ public: ASTNODE_NODE_FUNCS(ParseRef) virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } // * = Var name - virtual V3Hash sameHash() const override { return V3Hash(V3Hash(m_expect), V3Hash(m_name)); } virtual bool same(const AstNode* samep) const override { const AstParseRef* asamep = static_cast(samep); return (expect() == asamep->expect() && m_name == asamep->m_name); @@ -3026,7 +2991,7 @@ private: public: AstClassOrPackageRef(FileLine* fl, const string& name, AstNode* classOrPackageNodep, AstNode* paramsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_ClassOrPackageRef(fl) , m_name{name} , m_classOrPackageNodep{classOrPackageNodep} { addNOp4p(paramsp); @@ -3046,7 +3011,6 @@ public: return (m_classOrPackageNodep == static_cast(samep)->m_classOrPackageNodep); } - virtual V3Hash sameHash() const override { return V3Hash(m_classOrPackageNodep); } virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } // * = Var name AstNode* classOrPackageNodep() const { return m_classOrPackageNodep; } @@ -3063,7 +3027,7 @@ class AstDot final : public AstNode { bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) public: AstDot(FileLine* fl, bool colon, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Dot(fl) , m_colon{colon} { setOp1p(lhsp); setOp2p(rhsp); @@ -3085,7 +3049,7 @@ class AstUnbounded final : public AstNodeMath { // Due to where is used, treated as Signed32 public: explicit AstUnbounded(FileLine* fl) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Unbounded(fl) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(Unbounded) @@ -3100,7 +3064,7 @@ class AstTask final : public AstNodeFTask { // A task inside a module public: AstTask(FileLine* fl, const string& name, AstNode* stmtp) - : ASTGEN_SUPER(fl, name, stmtp) {} + : ASTGEN_SUPER_Task(fl, name, stmtp) {} ASTNODE_NODE_FUNCS(Task) }; @@ -3108,7 +3072,7 @@ class AstFunc final : public AstNodeFTask { // A function inside a module public: AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp) - : ASTGEN_SUPER(fl, name, stmtp) { + : ASTGEN_SUPER_Func(fl, name, stmtp) { addNOp1p(fvarsp); } ASTNODE_NODE_FUNCS(Func) @@ -3119,11 +3083,11 @@ class AstTaskRef final : public AstNodeFTaskRef { // A reference to a task public: AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER(fl, true, namep, pinsp) { + : ASTGEN_SUPER_TaskRef(fl, true, namep, pinsp) { statement(true); } AstTaskRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, true, name, pinsp) {} + : ASTGEN_SUPER_TaskRef(fl, true, name, pinsp) {} ASTNODE_NODE_FUNCS(TaskRef) }; @@ -3131,9 +3095,9 @@ class AstFuncRef final : public AstNodeFTaskRef { // A reference to a function public: AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, namep, pinsp) {} + : ASTGEN_SUPER_FuncRef(fl, false, namep, pinsp) {} AstFuncRef(FileLine* fl, const string& name, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, name, pinsp) {} + : ASTGEN_SUPER_FuncRef(fl, false, name, pinsp) {} ASTNODE_NODE_FUNCS(FuncRef) virtual bool hasDType() const override { return true; } }; @@ -3147,7 +3111,7 @@ private: string m_cname; // Name of function on c side public: AstDpiExport(FileLine* fl, const string& vname, const string& cname) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_DpiExport(fl) , m_name{vname} , m_cname{cname} {} ASTNODE_NODE_FUNCS(DpiExport) @@ -3164,13 +3128,12 @@ class AstWithParse final : public AstNodeStmt { // Children: funcref, math public: AstWithParse(FileLine* fl, bool stmt, AstNode* funcrefp, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_WithParse(fl) { statement(stmt); setOp1p(funcrefp); addNOp2p(exprp); } ASTNODE_NODE_FUNCS(WithParse) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstNode* funcrefp() const { return op1p(); } @@ -3187,11 +3150,10 @@ private: public: AstLambdaArgRef(FileLine* fl, const string& name, bool index) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_LambdaArgRef(fl) , m_name{name} , m_index(index) {} ASTNODE_NODE_FUNCS(LambdaArgRef) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual string emitVerilog() override { return name(); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } @@ -3213,13 +3175,12 @@ class AstWith final : public AstNodeStmt { public: AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_With(fl) { addOp1p(indexArgRefp); addOp2p(valueArgRefp); addNOp3p(exprp); } ASTNODE_NODE_FUNCS(With) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool hasDType() const override { return true; } virtual const char* broken() const override { @@ -3247,28 +3208,27 @@ public: class Settle {}; // for creator type-overload selection class Never {}; // for creator type-overload selection AstSenItem(FileLine* fl, VEdgeType edgeType, AstNode* varrefp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{edgeType} { setOp1p(varrefp); } AstSenItem(FileLine* fl, Combo) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_COMBO} {} AstSenItem(FileLine* fl, Illegal) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_ILLEGAL} {} AstSenItem(FileLine* fl, Initial) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_INITIAL} {} AstSenItem(FileLine* fl, Settle) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_SETTLE} {} AstSenItem(FileLine* fl, Never) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SenItem(fl) , m_edgeType{VEdgeType::ET_NEVER} {} ASTNODE_NODE_FUNCS(SenItem) virtual void dump(std::ostream& str) const override; - virtual V3Hash sameHash() const override { return V3Hash(edgeType()); } virtual bool same(const AstNode* samep) const override { return edgeType() == static_cast(samep)->edgeType(); } @@ -3299,13 +3259,12 @@ private: bool m_multi = false; // Created from combo logic by ORing multiple clock domains public: AstSenTree(FileLine* fl, AstSenItem* sensesp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SenTree(fl) { addNOp1p(sensesp); } ASTNODE_NODE_FUNCS(SenTree) virtual void dump(std::ostream& str) const override; virtual bool maybePointedTo() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } bool isMulti() const { return m_multi; } // op1 = Sensitivity list AstSenItem* sensesp() const { return VN_CAST(op1p(), SenItem); } @@ -3321,14 +3280,14 @@ public: class AstFinal final : public AstNodeProcedure { public: AstFinal(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) {} + : ASTGEN_SUPER_Final(fl, bodysp) {} ASTNODE_NODE_FUNCS(Final) }; class AstInitial final : public AstNodeProcedure { public: AstInitial(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) {} + : ASTGEN_SUPER_Initial(fl, bodysp) {} ASTNODE_NODE_FUNCS(Initial) }; @@ -3337,7 +3296,7 @@ class AstAlways final : public AstNodeProcedure { public: AstAlways(FileLine* fl, VAlwaysKwd keyword, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) + : ASTGEN_SUPER_Always(fl, bodysp) , m_keyword{keyword} { addNOp1p(sensesp); } @@ -3348,26 +3307,36 @@ public: void sensesp(AstSenTree* nodep) { setOp1p(nodep); } VAlwaysKwd keyword() const { return m_keyword; } }; + class AstAlwaysPostponed final : public AstNodeProcedure { // Like always but postponement scheduling region public: AstAlwaysPostponed(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER(fl, bodysp) {} + : ASTGEN_SUPER_AlwaysPostponed(fl, bodysp) {} ASTNODE_NODE_FUNCS(AlwaysPostponed) }; +class AstAlwaysPost final : public AstNodeProcedure { + // Like always but post assignments for memory assignment IFs +public: + AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) + : ASTGEN_SUPER_AlwaysPost(fl, bodysp) { + addNOp1p(sensesp); + } + ASTNODE_NODE_FUNCS(AlwaysPost) +}; + class AstAlwaysPublic final : public AstNodeStmt { // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ // Body statements are just AstVarRefs to the public signals public: AstAlwaysPublic(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_AlwaysPublic(fl) { addNOp1p(sensesp); addNOp2p(bodysp); } ASTNODE_NODE_FUNCS(AlwaysPublic) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } // op1 = Sensitivity list @@ -3377,24 +3346,10 @@ public: bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } }; -class AstAlwaysPost final : public AstNode { - // Like always but post assignments for memory assignment IFs -public: - AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { - addNOp1p(sensesp); - addNOp2p(bodysp); - } - ASTNODE_NODE_FUNCS(AlwaysPost) - // - AstNode* bodysp() const { return op2p(); } // op2 = Statements to evaluate - void addBodysp(AstNode* newp) { addOp2p(newp); } -}; - class AstAssign final : public AstNodeAssign { public: AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Assign(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Assign) @@ -3409,7 +3364,7 @@ class AstAssignAlias final : public AstNodeAssign { // If both sides are wires, there's no LHS vs RHS, public: AstAssignAlias(FileLine* fl, AstVarRef* lhsp, AstVarRef* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignAlias(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignAlias) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { V3ERROR_NA_RETURN(nullptr); @@ -3420,7 +3375,7 @@ public: class AstAssignDly final : public AstNodeAssign { public: AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignDly(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignDly) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignDly(this->fileline(), lhsp, rhsp); @@ -3434,7 +3389,7 @@ class AstAssignW final : public AstNodeAssign { // Like assign, but wire/assign's in verilog, the only setting of the specified variable public: AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignW(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignW) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignW(this->fileline(), lhsp, rhsp); @@ -3454,7 +3409,7 @@ class AstAssignVarScope final : public AstNodeAssign { // Assign two VarScopes to each other public: AstAssignVarScope(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_AssignVarScope(fl, lhsp, rhsp) { dtypeFrom(rhsp); } ASTNODE_NODE_FUNCS(AssignVarScope) @@ -3470,7 +3425,7 @@ private: public: AstPull(FileLine* fl, AstNode* lhsp, bool direction) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Pull(fl) { setOp1p(lhsp); m_direction = direction; } @@ -3487,7 +3442,7 @@ class AstAssignPre final : public AstNodeAssign { // Like Assign, but predelayed assignment requiring special order handling public: AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignPre(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignPre) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignPre(this->fileline(), lhsp, rhsp); @@ -3499,7 +3454,7 @@ class AstAssignPost final : public AstNodeAssign { // Like Assign, but predelayed assignment requiring special order handling public: AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_AssignPost(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(AssignPost) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAssignPost(this->fileline(), lhsp, rhsp); @@ -3513,7 +3468,7 @@ class AstExprStmt final : public AstNodeMath { // resultp is evaluated AFTER the statement(s). public: AstExprStmt(FileLine* fl, AstNode* stmtsp, AstNode* resultp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ExprStmt(fl) { addOp1p(stmtsp); setOp2p(resultp); // Possibly in future nullptr could mean return rhsp() dtypeFrom(resultp); @@ -3527,7 +3482,6 @@ public: virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode*) const override { return true; } }; @@ -3540,12 +3494,11 @@ private: string m_name; // Text of comment public: AstComment(FileLine* fl, const string& name, bool showAt = false) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Comment(fl) , m_showAt{showAt} , m_name{name} {} ASTNODE_NODE_FUNCS(Comment) virtual string name() const override { return m_name; } // * = Text - virtual V3Hash sameHash() const override { return V3Hash(); } // Ignore name in comments virtual bool same(const AstNode* samep) const override { return true; } // Ignore name in comments @@ -3558,7 +3511,7 @@ class AstCond final : public AstNodeCond { // Children: MATH public: AstCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : ASTGEN_SUPER(fl, condp, expr1p, expr2p) {} + : ASTGEN_SUPER_Cond(fl, condp, expr1p, expr2p) {} ASTNODE_NODE_FUNCS(Cond) virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { return new AstCond(this->fileline(), condp, expr1p, expr2p); @@ -3571,7 +3524,7 @@ class AstCondBound final : public AstNodeCond { // Children: MATH public: AstCondBound(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) - : ASTGEN_SUPER(fl, condp, expr1p, expr2p) {} + : ASTGEN_SUPER_CondBound(fl, condp, expr1p, expr2p) {} ASTNODE_NODE_FUNCS(CondBound) virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) override { return new AstCondBound(this->fileline(), condp, expr1p, expr2p); @@ -3594,7 +3547,7 @@ private: public: AstCoverDecl(FileLine* fl, const string& page, const string& comment, const string& linescov, int offset) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CoverDecl(fl) { m_page = page; m_text = comment; m_linescov = linescov; @@ -3625,7 +3578,6 @@ public: const string& hier() const { return m_hier; } void hier(const string& flag) { m_hier = flag; } void comment(const string& flag) { m_text = flag; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { const AstCoverDecl* asamep = static_cast(samep); return (fileline() == asamep->fileline() && linescov() == asamep->linescov() @@ -3647,7 +3599,7 @@ private: AstCoverDecl* m_declp; // [After V3Coverage] Pointer to declaration public: AstCoverInc(FileLine* fl, AstCoverDecl* declp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CoverInc(fl) , m_declp{declp} {} ASTNODE_NODE_FUNCS(CoverInc) virtual const char* broken() const override { @@ -3659,7 +3611,6 @@ public: } virtual void dump(std::ostream& str) const override; virtual int instrCount() const override { return 1 + 2 * instrCountLd(); } - virtual V3Hash sameHash() const override { return V3Hash(declp()); } virtual bool same(const AstNode* samep) const override { return declp() == static_cast(samep)->declp(); } @@ -3676,14 +3627,13 @@ class AstCoverToggle final : public AstNodeStmt { // Children: AstCoverInc, orig var, change det var public: AstCoverToggle(FileLine* fl, AstCoverInc* incp, AstNode* origp, AstNode* changep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CoverToggle(fl) { setOp1p(incp); setOp2p(origp); setOp3p(changep); } ASTNODE_NODE_FUNCS(CoverToggle) virtual int instrCount() const override { return 3 + instrCountBranch() + instrCountLd(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return true; } @@ -3701,11 +3651,10 @@ class AstDelay final : public AstNodeStmt { // Delay statement public: AstDelay(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Delay(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(Delay) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstNode* lhsp() const { return op1p(); } // op2 = Statements to evaluate @@ -3719,7 +3668,7 @@ class AstGenCase final : public AstNodeCase { // casesp Children: CASEITEMs public: AstGenCase(FileLine* fl, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER(fl, exprp, casesp) {} + : ASTGEN_SUPER_GenCase(fl, exprp, casesp) {} ASTNODE_NODE_FUNCS(GenCase) }; @@ -3737,7 +3686,7 @@ private: bool m_priorityPragma = false; // priority case public: AstCase(FileLine* fl, VCaseType casex, AstNode* exprp, AstNode* casesp) - : ASTGEN_SUPER(fl, exprp, casesp) + : ASTGEN_SUPER_Case(fl, exprp, casesp) , m_casex{casex} {} ASTNODE_NODE_FUNCS(Case) virtual string verilogKwd() const override { @@ -3772,7 +3721,7 @@ private: bool m_ignoreOverlap = false; // Default created by assertions; ignore overlaps public: AstCaseItem(FileLine* fl, AstNode* condsp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CaseItem(fl) { addNOp1p(condsp); addNOp2p(bodysp); } @@ -3799,7 +3748,7 @@ public: class NoFormat {}; AstSFormatF(FileLine* fl, const string& text, bool hidden, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SFormatF(fl) , m_text{text} , m_hidden{hidden} , m_hasFormat{true} @@ -3810,7 +3759,7 @@ public: } AstSFormatF(FileLine* fl, NoFormat, AstNode* exprsp, char missingArgChar = 'd', bool hidden = true) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SFormatF(fl) , m_text{""} , m_hidden{hidden} , m_hasFormat{false} @@ -3822,7 +3771,6 @@ public: ASTNODE_NODE_FUNCS(SFormatF) virtual string name() const override { return m_text; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool hasDType() const override { return true; } virtual bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); @@ -3855,14 +3803,14 @@ private: public: AstDisplay(FileLine* fl, AstDisplayType dispType, const string& text, AstNode* filep, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Display(fl) { setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); setNOp3p(filep); m_displayType = dispType; } AstDisplay(FileLine* fl, AstDisplayType dispType, AstNode* filep, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Display(fl) { setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); setNOp3p(filep); m_displayType = dispType; @@ -3884,7 +3832,6 @@ public: } // SPECIAL: $display has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(displayType()); } virtual bool same(const AstNode* samep) const override { return displayType() == static_cast(samep)->displayType(); } @@ -3906,7 +3853,7 @@ class AstDumpCtl final : public AstNodeStmt { VDumpCtlType m_ctlType; // Type of operation public: AstDumpCtl(FileLine* fl, VDumpCtlType ctlType, AstNode* exprp = nullptr) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_DumpCtl(fl) , m_ctlType{ctlType} { setNOp1p(exprp); } @@ -3917,7 +3864,6 @@ public: virtual bool isPredictOptimizable() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool cleanOut() const { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } VDumpCtlType ctlType() const { return m_ctlType; } AstNode* exprp() const { return op1p(); } // op2 = Expressions to output @@ -3932,7 +3878,7 @@ private: public: AstElabDisplay(FileLine* fl, AstDisplayType dispType, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ElabDisplay(fl) { setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp)); m_displayType = dispType; } @@ -3951,7 +3897,6 @@ public: } // SPECIAL: $display has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(displayType()); } virtual bool same(const AstNode* samep) const override { return displayType() == static_cast(samep)->displayType(); } @@ -3969,12 +3914,12 @@ class AstSFormat final : public AstNodeStmt { public: AstSFormat(FileLine* fl, AstNode* lhsp, const string& text, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SFormat(fl) { setOp1p(new AstSFormatF(fl, text, true, exprsp, missingArgChar)); setOp3p(lhsp); } AstSFormat(FileLine* fl, AstNode* lhsp, AstNode* exprsp, char missingArgChar = 'd') - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SFormat(fl) { setOp1p(new AstSFormatF(fl, AstSFormatF::NoFormat(), exprsp, missingArgChar)); setOp3p(lhsp); } @@ -3990,7 +3935,6 @@ public: virtual bool isOutputter() const override { return false; } virtual bool cleanOut() const { return false; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void fmtp(AstSFormatF* nodep) { addOp1p(nodep); } // op1 = To-String formatter AstSFormatF* fmtp() const { return VN_CAST(op1p(), SFormatF); } @@ -4004,7 +3948,7 @@ class AstSysFuncAsTask final : public AstNodeStmt { // Children: a system function public: AstSysFuncAsTask(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SysFuncAsTask(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(SysFuncAsTask) @@ -4014,7 +3958,6 @@ public: virtual bool isPure() const override { return true; } virtual bool isOutputter() const override { return false; } virtual int instrCount() const override { return 0; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* lhsp() const { return op1p(); } // op1 = Expressions to eval void lhsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to eval @@ -4025,7 +3968,7 @@ class AstSysIgnore final : public AstNodeStmt { // Children: varrefs or exprs public: AstSysIgnore(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SysIgnore(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(SysIgnore) @@ -4046,7 +3989,7 @@ class AstFClose final : public AstNodeStmt { // Children: file which must be a varref public: AstFClose(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FClose(fl) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FClose) @@ -4056,7 +3999,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } @@ -4066,7 +4008,7 @@ class AstFOpen final : public AstNodeStmt { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) public: AstFOpen(FileLine* fl, AstNode* filep, AstNode* filenamep, AstNode* modep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FOpen(fl) { setOp1p(filep); setOp2p(filenamep); setOp3p(modep); @@ -4079,7 +4021,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op1p(); } AstNode* filenamep() const { return op2p(); } @@ -4090,7 +4031,7 @@ class AstFOpenMcd final : public AstNodeStmt { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) public: AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FOpenMcd(fl) { setOp1p(filep); setOp2p(filenamep); } @@ -4102,7 +4043,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op1p(); } AstNode* filenamep() const { return op2p(); } @@ -4113,7 +4053,7 @@ class AstFFlush final : public AstNodeStmt { // Children: file which must be a varref public: AstFFlush(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FFlush(fl) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FFlush) @@ -4123,7 +4063,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } @@ -4137,7 +4076,7 @@ class AstFRead final : public AstNodeMath { // Children: count public: AstFRead(FileLine* fl, AstNode* memp, AstNode* filep, AstNode* startp, AstNode* countp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FRead(fl) { setOp1p(memp); setOp2p(filep); setNOp3p(startp); @@ -4152,7 +4091,6 @@ public: virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: makes output virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* memp() const { return op1p(); } void memp(AstNode* nodep) { setOp1p(nodep); } @@ -4169,7 +4107,7 @@ class AstFRewind final : public AstNodeMath { // Children: file which must be a varref public: AstFRewind(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FRewind(fl) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FRewind) @@ -4182,7 +4120,6 @@ public: virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } @@ -4193,7 +4130,7 @@ class AstFTell final : public AstNodeMath { // Children: file which must be a varref public: AstFTell(FileLine* fl, AstNode* filep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FTell(fl) { setNOp2p(filep); } ASTNODE_NODE_FUNCS(FTell) @@ -4206,7 +4143,6 @@ public: virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } @@ -4219,7 +4155,7 @@ class AstFSeek final : public AstNodeMath { // Children: operation public: AstFSeek(FileLine* fl, AstNode* filep, AstNode* offset, AstNode* operation) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FSeek(fl) { setOp2p(filep); setNOp3p(offset); setNOp4p(operation); @@ -4233,7 +4169,6 @@ public: virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: makes output virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* filep() const { return op2p(); } void filep(AstNode* nodep) { setOp2p(nodep); } @@ -4252,7 +4187,7 @@ private: public: AstFScanF(FileLine* fl, const string& text, AstNode* filep, AstNode* exprsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_FScanF(fl) , m_text{text} { addNOp1p(exprsp); setNOp2p(filep); @@ -4267,7 +4202,6 @@ public: virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: makes output virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); } @@ -4288,7 +4222,7 @@ private: public: AstSScanF(FileLine* fl, const string& text, AstNode* fromp, AstNode* exprsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_SScanF(fl) , m_text{text} { addNOp1p(exprsp); setOp2p(fromp); @@ -4303,7 +4237,6 @@ public: virtual bool isPure() const override { return false; } // SPECIAL: has 'visual' ordering virtual bool isOutputter() const override { return true; } // SPECIAL: makes output virtual bool cleanOut() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); } @@ -4334,7 +4267,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return isHex() == static_cast(samep)->isHex(); } @@ -4350,7 +4282,7 @@ class AstReadMem final : public AstNodeReadWriteMem { public: AstReadMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) - : ASTGEN_SUPER(fl, hex, filenamep, memp, lsbp, msbp) {} + : ASTGEN_SUPER_ReadMem(fl, hex, filenamep, memp, lsbp, msbp) {} ASTNODE_NODE_FUNCS(ReadMem); virtual string verilogKwd() const override { return (isHex() ? "$readmemh" : "$readmemb"); } virtual const char* cFuncPrefixp() const override { return "VL_READMEM_"; } @@ -4360,7 +4292,7 @@ class AstWriteMem final : public AstNodeReadWriteMem { public: AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) - : ASTGEN_SUPER(fl, hex, filenamep, memp, lsbp, msbp) {} + : ASTGEN_SUPER_WriteMem(fl, hex, filenamep, memp, lsbp, msbp) {} ASTNODE_NODE_FUNCS(WriteMem) virtual string verilogKwd() const override { return (isHex() ? "$writememh" : "$writememb"); } virtual const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; } @@ -4371,7 +4303,7 @@ class AstMonitorOff final : public AstNodeStmt { public: AstMonitorOff(FileLine* fl, bool off) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_MonitorOff(fl) , m_off{off} {} ASTNODE_NODE_FUNCS(MonitorOff) virtual string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } @@ -4382,7 +4314,6 @@ public: virtual bool isPure() const override { return false; } // Though deleted before opt virtual bool isOutputter() const override { return true; } // Though deleted before opt virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(m_off); } virtual bool same(const AstNode* samep) const override { return m_off == static_cast(samep)->m_off; } @@ -4393,7 +4324,7 @@ class AstSystemT final : public AstNodeStmt { // $system used as task public: AstSystemT(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SystemT(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(SystemT) @@ -4403,7 +4334,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* lhsp() const { return op1p(); } }; @@ -4412,7 +4342,7 @@ class AstSystemF final : public AstNodeMath { // $system used as function public: AstSystemF(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SystemF(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(SystemF) @@ -4425,7 +4355,6 @@ public: virtual bool isOutputter() const override { return true; } virtual bool isUnlikely() const override { return true; } virtual bool cleanOut() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* lhsp() const { return op1p(); } }; @@ -4435,7 +4364,7 @@ class AstValuePlusArgs final : public AstNodeMath { // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs public: AstValuePlusArgs(FileLine* fl, AstNode* searchp, AstNode* outp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ValuePlusArgs(fl) { setOp1p(searchp); setOp2p(outp); } @@ -4447,7 +4376,6 @@ public: virtual bool isHeavy() const override { return true; } virtual bool isPredictOptimizable() const override { return false; } virtual bool cleanOut() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* searchp() const { return op1p(); } // op1 = Search expression void searchp(AstNode* nodep) { setOp1p(nodep); } @@ -4463,7 +4391,7 @@ private: public: AstTestPlusArgs(FileLine* fl, const string& text) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TestPlusArgs(fl) , m_text{text} {} ASTNODE_NODE_FUNCS(TestPlusArgs) virtual string name() const override { return m_text; } @@ -4473,7 +4401,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual bool cleanOut() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(text()); } virtual bool same(const AstNode* samep) const override { return text() == static_cast(samep)->text(); } @@ -4484,14 +4411,14 @@ public: class AstGenFor final : public AstNodeFor { public: AstGenFor(FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) - : ASTGEN_SUPER(fl, initsp, condp, incsp, bodysp) {} + : ASTGEN_SUPER_GenFor(fl, initsp, condp, incsp, bodysp) {} ASTNODE_NODE_FUNCS(GenFor) }; class AstForeach final : public AstNodeStmt { public: AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Foreach(fl) { setOp1p(arrayp); addNOp4p(bodysp); } @@ -4500,14 +4427,13 @@ public: AstNode* bodysp() const { return op4p(); } // op4 = body of loop virtual bool isGateOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; class AstRepeat final : public AstNodeStmt { public: AstRepeat(FileLine* fl, AstNode* countp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Repeat(fl) { setOp2p(countp); addNOp3p(bodysp); } @@ -4518,14 +4444,13 @@ public: return false; } // Not relevant - converted to FOR virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; class AstWait final : public AstNodeStmt { public: AstWait(FileLine* fl, AstNode* condp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Wait(fl) { setOp2p(condp); addNOp3p(bodysp); } @@ -4536,7 +4461,7 @@ public: class AstWhile final : public AstNodeStmt { public: AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp, AstNode* incsp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_While(fl) { setOp2p(condp); addNOp3p(bodysp); addNOp4p(incsp); @@ -4552,7 +4477,6 @@ public: void addIncsp(AstNode* newp) { addOp4p(newp); } virtual bool isGateOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // Stop statement searchback here virtual void addBeforeStmt(AstNode* newp, AstNode* belowp) override; @@ -4563,10 +4487,9 @@ public: class AstBreak final : public AstNodeStmt { public: explicit AstBreak(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_Break(fl) {} ASTNODE_NODE_FUNCS(Break) virtual string verilogKwd() const override { return "break"; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool isBrancher() const override { return true; // SPECIAL: We don't process code after breaks } @@ -4575,10 +4498,9 @@ public: class AstContinue final : public AstNodeStmt { public: explicit AstContinue(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_Continue(fl) {} ASTNODE_NODE_FUNCS(Continue) virtual string verilogKwd() const override { return "continue"; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool isBrancher() const override { return true; // SPECIAL: We don't process code after breaks } @@ -4589,7 +4511,7 @@ private: string m_name; // Name of block public: AstDisable(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Disable(fl) , m_name{name} {} ASTNODE_NODE_FUNCS(Disable) virtual string name() const override { return m_name; } // * = Block name @@ -4603,7 +4525,7 @@ class AstDisableFork final : public AstNodeStmt { // A "disable fork" statement public: explicit AstDisableFork(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_DisableFork(fl) {} ASTNODE_NODE_FUNCS(DisableFork) }; @@ -4611,19 +4533,18 @@ class AstWaitFork final : public AstNodeStmt { // A "wait fork" statement public: explicit AstWaitFork(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_WaitFork(fl) {} ASTNODE_NODE_FUNCS(WaitFork) }; class AstReturn final : public AstNodeStmt { public: explicit AstReturn(FileLine* fl, AstNode* lhsp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Return(fl) { setNOp1p(lhsp); } ASTNODE_NODE_FUNCS(Return) virtual string verilogKwd() const override { return "return"; } - virtual V3Hash sameHash() const override { return V3Hash(); } AstNode* lhsp() const { return op1p(); } virtual bool isBrancher() const override { return true; // SPECIAL: We don't process code after breaks @@ -4633,7 +4554,7 @@ public: class AstGenIf final : public AstNodeIf { public: AstGenIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) - : ASTGEN_SUPER(fl, condp, ifsp, elsesp) {} + : ASTGEN_SUPER_GenIf(fl, condp, ifsp, elsesp) {} ASTNODE_NODE_FUNCS(GenIf) }; @@ -4644,7 +4565,7 @@ private: bool m_priorityPragma; // priority case public: AstIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp = nullptr) - : ASTGEN_SUPER(fl, condp, ifsp, elsesp) { + : ASTGEN_SUPER_If(fl, condp, ifsp, elsesp) { m_uniquePragma = false; m_unique0Pragma = false; m_priorityPragma = false; @@ -4668,7 +4589,7 @@ private: public: // After construction must call ->labelp to associate with appropriate label AstJumpBlock(FileLine* fl, AstNode* stmtsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_JumpBlock(fl) { addNOp1p(stmtsp); } virtual const char* broken() const override; @@ -4676,7 +4597,6 @@ public: ASTNODE_NODE_FUNCS(JumpBlock) virtual int instrCount() const override { return 0; } virtual bool maybePointedTo() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // op1 = Statements AstNode* stmtsp() const { return op1p(); } // op1 = List of statements @@ -4697,7 +4617,7 @@ private: AstJumpBlock* m_blockp; // [After V3Jump] Pointer to declaration public: AstJumpLabel(FileLine* fl, AstJumpBlock* blockp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_JumpLabel(fl) , m_blockp{blockp} {} ASTNODE_NODE_FUNCS(JumpLabel) virtual bool maybePointedTo() const override { return true; } @@ -4711,7 +4631,6 @@ public: } virtual void dump(std::ostream& str) const override; virtual int instrCount() const override { return 0; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return blockp() == static_cast(samep)->blockp(); } @@ -4727,7 +4646,7 @@ private: AstJumpLabel* m_labelp; // [After V3Jump] Pointer to declaration public: AstJumpGo(FileLine* fl, AstJumpLabel* labelp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_JumpGo(fl) , m_labelp{labelp} {} ASTNODE_NODE_FUNCS(JumpGo); virtual const char* broken() const override { @@ -4739,7 +4658,6 @@ public: } virtual void dump(std::ostream& str) const override; virtual int instrCount() const override { return instrCountBranch(); } - virtual V3Hash sameHash() const override { return V3Hash(labelp()); } virtual bool same(const AstNode* samep) const override { return labelp() == static_cast(samep)->labelp(); } @@ -4757,7 +4675,7 @@ class AstChangeXor final : public AstNodeBiComAsv { // Children: VARREF public: AstChangeXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ChangeXor(fl, lhsp, rhsp) { dtypeSetUInt32(); // Always used on, and returns word entities } ASTNODE_NODE_FUNCS(ChangeXor) @@ -4785,7 +4703,7 @@ private: public: // Null lhs+rhs used to indicate change needed with no spec vars AstChangeDet(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool clockReq) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ChangeDet(fl) { setNOp1p(lhsp); setNOp2p(rhsp); m_clockReq = clockReq; @@ -4797,7 +4715,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4807,7 +4724,7 @@ class AstConsAssoc final : public AstNodeMath { // Children: expression (elements or other queues) public: AstConsAssoc(FileLine* fl, AstNode* defaultp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ConsAssoc(fl) { setNOp1p(defaultp); } ASTNODE_NODE_FUNCS(ConsAssoc) @@ -4817,7 +4734,6 @@ public: virtual bool cleanOut() const override { return true; } virtual int instrCount() const override { return widthInstrs(); } AstNode* defaultp() const { return op1p(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; class AstSetAssoc final : public AstNodeMath { @@ -4826,7 +4742,7 @@ class AstSetAssoc final : public AstNodeMath { // Children: expression (elements or other queues) public: AstSetAssoc(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* valuep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_SetAssoc(fl) { setOp1p(lhsp); setNOp2p(keyp); setOp3p(valuep); @@ -4840,7 +4756,6 @@ public: AstNode* lhsp() const { return op1p(); } AstNode* keyp() const { return op2p(); } AstNode* valuep() const { return op3p(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4850,7 +4765,7 @@ class AstConsDynArray final : public AstNodeMath { // Children: expression (elements or other queues) public: explicit AstConsDynArray(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ConsDynArray(fl) { setNOp1p(lhsp); setNOp2p(rhsp); } @@ -4862,7 +4777,6 @@ public: virtual int instrCount() const override { return widthInstrs(); } AstNode* lhsp() const { return op1p(); } // op1 = expression AstNode* rhsp() const { return op2p(); } // op2 = expression - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4872,7 +4786,7 @@ class AstConsQueue final : public AstNodeMath { // Children: expression (elements or other queues) public: explicit AstConsQueue(FileLine* fl, AstNode* lhsp = nullptr, AstNode* rhsp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ConsQueue(fl) { setNOp1p(lhsp); setNOp2p(rhsp); } @@ -4884,7 +4798,6 @@ public: virtual int instrCount() const override { return widthInstrs(); } AstNode* lhsp() const { return op1p(); } // op1 = expression AstNode* rhsp() const { return op2p(); } // op2 = expression - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -4899,7 +4812,7 @@ public: // Node that simply puts name into the output stream AstBegin(FileLine* fl, const string& name, AstNode* stmtsp, bool generate = false, bool implied = false) - : ASTGEN_SUPER(fl, name, stmtsp) + : ASTGEN_SUPER_Begin(fl, name, stmtsp) , m_generate{generate} , m_implied{implied} {} ASTNODE_NODE_FUNCS(Begin) @@ -4922,7 +4835,7 @@ private: public: // Node that simply puts name into the output stream AstFork(FileLine* fl, const string& name, AstNode* stmtsp) - : ASTGEN_SUPER(fl, name, stmtsp) {} + : ASTGEN_SUPER_Fork(fl, name, stmtsp) {} ASTNODE_NODE_FUNCS(Fork) virtual void dump(std::ostream& str) const override; VJoinType joinType() const { return m_joinType; } @@ -4932,7 +4845,7 @@ public: class AstInside final : public AstNodeMath { public: AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Inside(fl) { addOp1p(exprp); addOp2p(itemsp); dtypeSetBit(); @@ -4949,7 +4862,7 @@ public: class AstInsideRange final : public AstNodeMath { public: AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_InsideRange(fl) { addOp1p(lhsp); addOp2p(rhsp); } @@ -4970,13 +4883,12 @@ class AstInitItem final : public AstNode { public: // Parents: INITARRAY AstInitItem(FileLine* fl, AstNode* valuep) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_InitItem(fl) { addOp1p(valuep); } ASTNODE_NODE_FUNCS(InitItem) virtual bool maybePointedTo() const override { return true; } virtual bool hasDType() const override { return false; } // See valuep()'s dtype instead - virtual V3Hash sameHash() const override { return V3Hash(); } AstNode* valuep() const { return op1p(); } // op1 = Value void valuep(AstNode* nodep) { addOp1p(nodep); } }; @@ -4995,7 +4907,7 @@ private: KeyItemMap m_map; // Node value for each array index public: AstInitArray(FileLine* fl, AstNodeArrayDType* newDTypep, AstNode* defaultp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_InitArray(fl) { dtypep(newDTypep); addNOp1p(defaultp); } @@ -5014,7 +4926,6 @@ public: } } virtual bool hasDType() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { // Only works if exact same children, instead should override comparison // of children list, and instead use map-vs-map key/value compare @@ -5061,9 +4972,8 @@ class AstNew final : public AstNodeFTaskRef { // Children: varref|arraysel, math public: AstNew(FileLine* fl, AstNode* pinsp) - : ASTGEN_SUPER(fl, false, "new", pinsp) {} + : ASTGEN_SUPER_New(fl, false, "new", pinsp) {} ASTNODE_NODE_FUNCS(New) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool cleanOut() const { return true; } virtual bool same(const AstNode* samep) const override { return true; } virtual bool hasDType() const override { return true; } @@ -5076,12 +4986,11 @@ class AstNewCopy final : public AstNodeMath { // Children: varref|arraysel, math public: AstNewCopy(FileLine* fl, AstNode* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_NewCopy(fl) { dtypeFrom(rhsp); // otherwise V3Width will resolve setNOp1p(rhsp); } ASTNODE_NODE_FUNCS(NewCopy) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual string emitVerilog() override { return "new"; } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } @@ -5096,13 +5005,12 @@ class AstNewDynamic final : public AstNodeMath { // Children: varref|arraysel, math public: AstNewDynamic(FileLine* fl, AstNode* sizep, AstNode* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_NewDynamic(fl) { dtypeFrom(rhsp); // otherwise V3Width will resolve setNOp1p(sizep); setNOp2p(rhsp); } ASTNODE_NODE_FUNCS(NewDynamic) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual string emitVerilog() override { return "new"; } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } @@ -5119,11 +5027,10 @@ public: // Pragmas don't result in any output code, they're just flags that affect // other processing in verilator. AstPragma(FileLine* fl, AstPragmaType pragType) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Pragma(fl) , m_pragType{pragType} {} ASTNODE_NODE_FUNCS(Pragma) AstPragmaType pragType() const { return m_pragType; } // *=type of the pragma - virtual V3Hash sameHash() const override { return V3Hash(pragType()); } virtual bool isPredictOptimizable() const override { return false; } virtual bool same(const AstNode* samep) const override { return pragType() == static_cast(samep)->pragType(); @@ -5136,7 +5043,7 @@ class AstPrintTimeScale final : public AstNodeStmt { VTimescale m_timeunit; // Parent module time unit public: explicit AstPrintTimeScale(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_PrintTimeScale(fl) {} ASTNODE_NODE_FUNCS(PrintTimeScale) virtual void name(const string& name) override { m_name = name; } virtual string name() const override { return m_name; } // * = Var name @@ -5147,7 +5054,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } void timeunit(const VTimescale& flag) { m_timeunit = flag; } VTimescale timeunit() const { return m_timeunit; } }; @@ -5155,7 +5061,7 @@ public: class AstStop final : public AstNodeStmt { public: AstStop(FileLine* fl, bool maybe) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_Stop(fl) {} ASTNODE_NODE_FUNCS(Stop) virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } @@ -5165,7 +5071,6 @@ public: virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const override { return true; } virtual int instrCount() const override { return 0; } // Rarely executes - virtual V3Hash sameHash() const override { return V3Hash(fileline()->lineno()); } virtual bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } @@ -5174,7 +5079,7 @@ public: class AstFinish final : public AstNodeStmt { public: explicit AstFinish(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_Finish(fl) {} ASTNODE_NODE_FUNCS(Finish) virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } @@ -5184,7 +5089,6 @@ public: virtual bool isOutputter() const override { return true; } // SPECIAL: $display makes output virtual bool isUnlikely() const override { return true; } virtual int instrCount() const override { return 0; } // Rarely executes - virtual V3Hash sameHash() const override { return V3Hash(fileline()->lineno()); } virtual bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } @@ -5195,7 +5099,7 @@ class AstNullCheck final : public AstNodeUniop { // Children: VarRef or something returning pointer public: AstNullCheck(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_NullCheck(fl, lhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(NullCheck) @@ -5207,7 +5111,6 @@ public: virtual bool cleanOut() const override { return true; } virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(fileline()->lineno()); } virtual bool same(const AstNode* samep) const override { return fileline() == samep->fileline(); } @@ -5217,7 +5120,7 @@ class AstTimingControl final : public AstNodeStmt { // Parents: stmtlist public: AstTimingControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_TimingControl(fl) { setNOp1p(sensesp); setNOp2p(stmtsp); } @@ -5228,7 +5131,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return false; } virtual int instrCount() const override { return 0; } - virtual V3Hash sameHash() const override { return V3Hash(); } AstSenTree* sensesp() const { return VN_CAST(op1p(), SenTree); } AstNode* stmtsp() const { return op2p(); } }; @@ -5238,7 +5140,7 @@ class AstTimeFormat final : public AstNodeStmt { public: AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp, AstNode* widthp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_TimeFormat(fl) { setOp1p(unitsp); setOp2p(precisionp); setOp3p(suffixp); @@ -5251,7 +5153,6 @@ public: virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } AstNode* unitsp() const { return op1p(); } AstNode* precisionp() const { return op2p(); } AstNode* suffixp() const { return op3p(); } @@ -5278,7 +5179,7 @@ public: AstVar* varp, // For input/output state etc AstNode* valuep, const VNumRange& bitRange, const VNumRange& arrayRange, bool isScoped) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TraceDecl(fl) , m_showname{showname} , m_bitRange{bitRange} , m_arrayRange{arrayRange} @@ -5323,7 +5224,7 @@ private: const bool m_full; // Is this a full vs incremental dump public: AstTraceInc(FileLine* fl, AstTraceDecl* declp, bool full) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TraceInc(fl) , m_declp{declp} , m_full{full} { dtypeFrom(declp); @@ -5340,7 +5241,6 @@ public: virtual void dump(std::ostream& str) const override; virtual int instrCount() const override { return 10 + 2 * instrCountLd(); } virtual bool hasDType() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(declp()); } virtual bool same(const AstNode* samep) const override { return declp() == static_cast(samep)->declp(); } @@ -5366,7 +5266,7 @@ private: public: AstActive(FileLine* fl, const string& name, AstSenTree* sensesp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Active(fl) { m_name = name; // Copy it UASSERT(sensesp, "Sensesp required arg"); m_sensesp = sensesp; @@ -5406,7 +5306,7 @@ private: public: AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp = nullptr, AstNode* dimp = nullptr) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_AttrOf(fl) { setNOp1p(fromp); setNOp2p(dimp); m_attrType = attrtype; @@ -5415,7 +5315,6 @@ public: AstNode* fromp() const { return op1p(); } AstNode* dimp() const { return op2p(); } AstAttrType attrType() const { return m_attrType; } - virtual V3Hash sameHash() const override { return V3Hash(m_attrType); } virtual void dump(std::ostream& str = std::cout) const override; }; @@ -5430,11 +5329,10 @@ private: public: explicit AstScopeName(FileLine* fl) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_ScopeName(fl) { dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(ScopeName) - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return m_dpiExport == static_cast(samep)->m_dpiExport; } @@ -5464,7 +5362,7 @@ public: class AstUdpTable final : public AstNode { public: AstUdpTable(FileLine* fl, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UdpTable(fl) { addNOp1p(bodysp); } ASTNODE_NODE_FUNCS(UdpTable) @@ -5477,7 +5375,7 @@ class AstUdpTableLine final : public AstNode { public: AstUdpTableLine(FileLine* fl, const string& text) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_UdpTableLine(fl) , m_text{text} {} ASTNODE_NODE_FUNCS(UdpTableLine) virtual string name() const override { return m_text; } @@ -5496,12 +5394,12 @@ private: public: class Reset {}; AstRand(FileLine* fl, Reset, AstNodeDType* dtp, bool reset) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Rand(fl) , m_reset{reset} { dtypep(dtp); } AstRand(FileLine* fl, AstNode* seedp, bool urandom) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Rand(fl) , m_urandom(urandom) { setNOp1p(seedp); } @@ -5519,7 +5417,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstNode* seedp() const { return op1p(); } bool reset() const { return m_reset; } @@ -5530,7 +5427,7 @@ class AstURandomRange final : public AstNodeBiop { // $urandom_range public: explicit AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_URandomRange(fl, lhsp, rhsp) { dtypeSetUInt32(); // Says IEEE } ASTNODE_NODE_FUNCS(URandomRange) @@ -5556,7 +5453,7 @@ class AstTime final : public AstNodeTermop { VTimescale m_timeunit; // Parent module time unit public: AstTime(FileLine* fl, const VTimescale& timeunit) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_Time(fl) , m_timeunit{timeunit} { dtypeSetUInt64(); } @@ -5567,7 +5464,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountTime(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual void dump(std::ostream& str = std::cout) const override; void timeunit(const VTimescale& flag) { m_timeunit = flag; } @@ -5578,7 +5474,7 @@ class AstTimeD final : public AstNodeTermop { VTimescale m_timeunit; // Parent module time unit public: AstTimeD(FileLine* fl, const VTimescale& timeunit) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_TimeD(fl) , m_timeunit{timeunit} { dtypeSetDouble(); } @@ -5589,7 +5485,6 @@ public: virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountTime(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual void dump(std::ostream& str = std::cout) const override; void timeunit(const VTimescale& flag) { m_timeunit = flag; } @@ -5601,7 +5496,7 @@ class AstUCFunc final : public AstNodeMath { // Perhaps this should be an AstNodeListop; but there's only one list math right now public: AstUCFunc(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UCFunc(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(UCFunc) @@ -5615,7 +5510,6 @@ public: virtual bool isSubstOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -5625,7 +5519,7 @@ public: class AstNegate final : public AstNodeUniop { public: AstNegate(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Negate(fl, lhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Negate) @@ -5640,7 +5534,7 @@ public: class AstNegateD final : public AstNodeUniop { public: AstNegateD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_NegateD(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(NegateD) @@ -5657,7 +5551,7 @@ public: class AstRedAnd final : public AstNodeUniop { public: AstRedAnd(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RedAnd(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedAnd) @@ -5671,7 +5565,7 @@ public: class AstRedOr final : public AstNodeUniop { public: AstRedOr(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RedOr(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedOr) @@ -5685,7 +5579,7 @@ public: class AstRedXor final : public AstNodeUniop { public: AstRedXor(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RedXor(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedXor) @@ -5705,7 +5599,7 @@ class AstLenN final : public AstNodeUniop { // Length of a string public: AstLenN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_LenN(fl, lhsp) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(LenN) @@ -5719,7 +5613,7 @@ public: class AstLogNot final : public AstNodeUniop { public: AstLogNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_LogNot(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogNot) @@ -5734,7 +5628,7 @@ public: class AstNot final : public AstNodeUniop { public: AstNot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Not(fl, lhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Not) @@ -5750,9 +5644,9 @@ class AstExtend final : public AstNodeUniop { // Expand a value into a wider entity by 0 extension. Width is implied from nodep->width() public: AstExtend(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_Extend(fl, lhsp) {} AstExtend(FileLine* fl, AstNode* lhsp, int width) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Extend(fl, lhsp) { dtypeSetLogicSized(width, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(Extend) @@ -5770,10 +5664,10 @@ class AstExtendS final : public AstNodeUniop { // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() public: AstExtendS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_ExtendS(fl, lhsp) {} AstExtendS(FileLine* fl, AstNode* lhsp, int width) // Important that widthMin be correct, as opExtend requires it after V3Expand - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_ExtendS(fl, lhsp) { dtypeSetLogicSized(width, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ExtendS) @@ -5794,7 +5688,7 @@ class AstSigned final : public AstNodeUniop { // $signed(lhs) public: AstSigned(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Signed(fl, lhsp) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, "not coded to create after dtypes resolved"); } @@ -5814,7 +5708,7 @@ class AstUnsigned final : public AstNodeUniop { // $unsigned(lhs) public: AstUnsigned(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_Unsigned(fl, lhsp) { UASSERT_OBJ(!v3Global.assertDTypesResolved(), this, "not coded to create after dtypes resolved"); } @@ -5834,7 +5728,7 @@ class AstRToIS final : public AstNodeUniop { // $rtoi(lhs) public: AstRToIS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RToIS(fl, lhsp) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(RToIS) @@ -5850,7 +5744,7 @@ class AstRToIRoundS final : public AstNodeUniop { // Convert real to integer, with arbitrary sized output (not just "integer" format) public: AstRToIRoundS(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RToIRoundS(fl, lhsp) { dtypeSetSigned32(); } ASTNODE_NODE_FUNCS(RToIRoundS) @@ -5868,7 +5762,7 @@ class AstIToRD final : public AstNodeUniop { // $itor where lhs is unsigned public: AstIToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_IToRD(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(IToRD) @@ -5884,7 +5778,7 @@ class AstISToRD final : public AstNodeUniop { // $itor where lhs is signed public: AstISToRD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_ISToRD(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(ISToRD) @@ -5900,7 +5794,7 @@ public: class AstRealToBits final : public AstNodeUniop { public: AstRealToBits(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_RealToBits(fl, lhsp) { dtypeSetUInt64(); } ASTNODE_NODE_FUNCS(RealToBits) @@ -5917,7 +5811,7 @@ public: class AstBitsToRealD final : public AstNodeUniop { public: AstBitsToRealD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_BitsToRealD(fl, lhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(BitsToRealD) @@ -5935,7 +5829,7 @@ public: class AstCLog2 final : public AstNodeUniop { public: AstCLog2(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CLog2(fl, lhsp) {} ASTNODE_NODE_FUNCS(CLog2) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCLog2(lhs); } virtual string emitVerilog() override { return "%f$clog2(%l)"; } @@ -5949,11 +5843,12 @@ class AstCountBits final : public AstNodeQuadop { // Number of bits set in vector public: AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p) - : ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), ctrl1p->cloneTree(false)) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl1p->cloneTree(false), + ctrl1p->cloneTree(false)) {} AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p) - : ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl2p->cloneTree(false)) {} AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p, AstNode* ctrl2p, AstNode* ctrl3p) - : ASTGEN_SUPER(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} + : ASTGEN_SUPER_CountBits(fl, exprp, ctrl1p, ctrl2p, ctrl3p) {} ASTNODE_NODE_FUNCS(CountBits) virtual void numberOperate(V3Number& out, const V3Number& expr, const V3Number& ctrl1, const V3Number& ctrl2, const V3Number& ctrl3) override { @@ -5976,7 +5871,7 @@ class AstCountOnes final : public AstNodeUniop { // Number of bits set in vector public: AstCountOnes(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CountOnes(fl, lhsp) {} ASTNODE_NODE_FUNCS(CountOnes) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCountOnes(lhs); @@ -5992,7 +5887,7 @@ class AstIsUnknown final : public AstNodeUniop { // True if any unknown bits public: AstIsUnknown(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_IsUnknown(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(IsUnknown) @@ -6009,7 +5904,7 @@ class AstIsUnbounded final : public AstNodeUniop { // True if is unmbounded ($) public: AstIsUnbounded(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_IsUnbounded(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(IsUnbounded) @@ -6027,7 +5922,7 @@ class AstOneHot final : public AstNodeUniop { // True if only single bit set in vector public: AstOneHot(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_OneHot(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(OneHot) @@ -6043,7 +5938,7 @@ class AstOneHot0 final : public AstNodeUniop { // True if only single bit, or no bits set in vector public: AstOneHot0(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_OneHot0(fl, lhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(OneHot0) @@ -6060,13 +5955,13 @@ class AstCast final : public AstNode { // Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc public: AstCast(FileLine* fl, AstNode* lhsp, VFlagChildDType, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Cast(fl) { setOp1p(lhsp); setOp2p(dtp); dtypeFrom(dtp); } AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Cast(fl) { setOp1p(lhsp); dtypeFrom(dtp); } @@ -6094,7 +5989,7 @@ class AstCastDynamic final : public AstNodeBiop { // value reading from. Suggest use fromp()/top() instead of lhsp/rhsp(). public: AstCastDynamic(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_CastDynamic(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(CastDynamic) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { V3ERROR_NA; @@ -6119,7 +6014,7 @@ class AstCastParse final : public AstNode { // Cast to appropriate type, where we haven't determined yet what the data type is public: AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CastParse(fl) { setOp1p(lhsp); setOp2p(dtp); } @@ -6137,7 +6032,7 @@ class AstCastSize final : public AstNode { // Cast to specific size; signed/twostate inherited from lower element per IEEE public: AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CastSize(fl) { setOp1p(lhsp); setOp2p(rhsp); } @@ -6158,7 +6053,7 @@ private: public: AstCCast(FileLine* fl, AstNode* lhsp, int setwidth, int minwidth = -1) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_CCast(fl, lhsp) { m_size = setwidth; if (setwidth) { if (minwidth == -1) minwidth = setwidth; @@ -6166,7 +6061,7 @@ public: } } AstCCast(FileLine* fl, AstNode* lhsp, AstNode* typeFromp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_CCast(fl, lhsp) { dtypeFrom(typeFromp); m_size = width(); } @@ -6177,7 +6072,6 @@ public: virtual bool cleanOut() const override { return true; } virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } // Special cased in V3Cast - virtual V3Hash sameHash() const override { return V3Hash(size()); } virtual bool same(const AstNode* samep) const override { return size() == static_cast(samep)->size(); } @@ -6190,7 +6084,7 @@ class AstCvtPackString final : public AstNodeUniop { // Convert to Verilator Packed String (aka verilog "string") public: AstCvtPackString(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_CvtPackString(fl, lhsp) { dtypeSetString(); } ASTNODE_NODE_FUNCS(CvtPackString) @@ -6200,14 +6094,13 @@ public: virtual bool cleanOut() const override { return true; } virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; class AstFEof final : public AstNodeUniop { public: AstFEof(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_FEof(fl, lhsp) {} ASTNODE_NODE_FUNCS(FEof) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } virtual string emitVerilog() override { return "%f$feof(%l)"; } @@ -6225,7 +6118,7 @@ public: class AstFError final : public AstNodeMath { public: AstFError(FileLine* fl, AstNode* filep, AstNode* strp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_FError(fl) { setOp1p(filep); setOp2p(strp); } @@ -6243,14 +6136,13 @@ public: AstNode* filep() const { return op1p(); } void strp(AstNode* nodep) { setOp2p(nodep); } AstNode* strp() const { return op2p(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; class AstFGetC final : public AstNodeUniop { public: AstFGetC(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_FGetC(fl, lhsp) {} ASTNODE_NODE_FUNCS(FGetC) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } virtual string emitVerilog() override { return "%f$fgetc(%l)"; } @@ -6269,7 +6161,7 @@ public: class AstFUngetC final : public AstNodeBiop { public: AstFUngetC(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_FUngetC(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(FUngetC) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override { V3ERROR_NA; @@ -6312,7 +6204,7 @@ public: class AstLogD final : public AstNodeSystemUniop { public: AstLogD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_LogD(fl, lhsp) {} ASTNODE_NODE_FUNCS(LogD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::log(lhs.toDouble())); @@ -6323,7 +6215,7 @@ public: class AstLog10D final : public AstNodeSystemUniop { public: AstLog10D(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_Log10D(fl, lhsp) {} ASTNODE_NODE_FUNCS(Log10D) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::log10(lhs.toDouble())); @@ -6335,7 +6227,7 @@ public: class AstExpD final : public AstNodeSystemUniop { public: AstExpD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_ExpD(fl, lhsp) {} ASTNODE_NODE_FUNCS(ExpD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::exp(lhs.toDouble())); @@ -6347,7 +6239,7 @@ public: class AstSqrtD final : public AstNodeSystemUniop { public: AstSqrtD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_SqrtD(fl, lhsp) {} ASTNODE_NODE_FUNCS(SqrtD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::sqrt(lhs.toDouble())); @@ -6359,7 +6251,7 @@ public: class AstFloorD final : public AstNodeSystemUniop { public: AstFloorD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_FloorD(fl, lhsp) {} ASTNODE_NODE_FUNCS(FloorD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::floor(lhs.toDouble())); @@ -6371,7 +6263,7 @@ public: class AstCeilD final : public AstNodeSystemUniop { public: AstCeilD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CeilD(fl, lhsp) {} ASTNODE_NODE_FUNCS(CeilD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::ceil(lhs.toDouble())); @@ -6383,7 +6275,7 @@ public: class AstSinD final : public AstNodeSystemUniop { public: AstSinD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_SinD(fl, lhsp) {} ASTNODE_NODE_FUNCS(SinD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::sin(lhs.toDouble())); @@ -6395,7 +6287,7 @@ public: class AstCosD final : public AstNodeSystemUniop { public: AstCosD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CosD(fl, lhsp) {} ASTNODE_NODE_FUNCS(CosD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::cos(lhs.toDouble())); @@ -6407,7 +6299,7 @@ public: class AstTanD final : public AstNodeSystemUniop { public: AstTanD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_TanD(fl, lhsp) {} ASTNODE_NODE_FUNCS(TanD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::tan(lhs.toDouble())); @@ -6419,7 +6311,7 @@ public: class AstAsinD final : public AstNodeSystemUniop { public: AstAsinD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AsinD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AsinD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::asin(lhs.toDouble())); @@ -6431,7 +6323,7 @@ public: class AstAcosD final : public AstNodeSystemUniop { public: AstAcosD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AcosD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AcosD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::acos(lhs.toDouble())); @@ -6443,7 +6335,7 @@ public: class AstAtanD final : public AstNodeSystemUniop { public: AstAtanD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AtanD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AtanD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::atan(lhs.toDouble())); @@ -6455,7 +6347,7 @@ public: class AstSinhD final : public AstNodeSystemUniop { public: AstSinhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_SinhD(fl, lhsp) {} ASTNODE_NODE_FUNCS(SinhD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::sinh(lhs.toDouble())); @@ -6467,7 +6359,7 @@ public: class AstCoshD final : public AstNodeSystemUniop { public: AstCoshD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_CoshD(fl, lhsp) {} ASTNODE_NODE_FUNCS(CoshD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::cosh(lhs.toDouble())); @@ -6479,7 +6371,7 @@ public: class AstTanhD final : public AstNodeSystemUniop { public: AstTanhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_TanhD(fl, lhsp) {} ASTNODE_NODE_FUNCS(TanhD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::tanh(lhs.toDouble())); @@ -6491,7 +6383,7 @@ public: class AstAsinhD final : public AstNodeSystemUniop { public: AstAsinhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AsinhD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AsinhD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::asinh(lhs.toDouble())); @@ -6503,7 +6395,7 @@ public: class AstAcoshD final : public AstNodeSystemUniop { public: AstAcoshD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AcoshD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AcoshD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::acosh(lhs.toDouble())); @@ -6515,7 +6407,7 @@ public: class AstAtanhD final : public AstNodeSystemUniop { public: AstAtanhD(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_AtanhD(fl, lhsp) {} ASTNODE_NODE_FUNCS(AtanhD) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.setDouble(std::atanh(lhs.toDouble())); @@ -6527,7 +6419,7 @@ class AstToLowerN final : public AstNodeUniop { // string.tolower() public: AstToLowerN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_ToLowerN(fl, lhsp) { dtypeSetString(); } ASTNODE_NODE_FUNCS(ToLowerN) @@ -6544,7 +6436,7 @@ class AstToUpperN final : public AstNodeUniop { // string.toupper() public: AstToUpperN(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) { + : ASTGEN_SUPER_ToUpperN(fl, lhsp) { dtypeSetString(); } ASTNODE_NODE_FUNCS(ToUpperN) @@ -6562,7 +6454,7 @@ class AstTimeImport final : public AstNodeUniop { VTimescale m_timeunit; // Parent module time unit public: AstTimeImport(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl, lhsp) {} + : ASTGEN_SUPER_TimeImport(fl, lhsp) {} ASTNODE_NODE_FUNCS(TimeImport) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { V3ERROR_NA; } virtual string emitVerilog() override { return "%l"; } @@ -6584,7 +6476,7 @@ private: FmtType m_fmt; // Operation type public: AstAtoN(FileLine* fl, AstNode* lhsp, FmtType fmt) - : ASTGEN_SUPER(fl, lhsp) + : ASTGEN_SUPER_AtoN(fl, lhsp) , m_fmt{fmt} { fmt == ATOREAL ? dtypeSetDouble() : dtypeSetSigned32(); } @@ -6626,7 +6518,7 @@ public: class AstLogOr final : public AstNodeBiop { public: AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LogOr(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogOr) @@ -6649,7 +6541,7 @@ public: class AstLogAnd final : public AstNodeBiop { public: AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LogAnd(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogAnd) @@ -6672,7 +6564,7 @@ public: class AstLogEq final : public AstNodeBiCom { public: AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LogEq(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogEq) @@ -6695,7 +6587,7 @@ public: class AstLogIf final : public AstNodeBiop { public: AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LogIf(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogIf) @@ -6718,7 +6610,7 @@ public: class AstOr final : public AstNodeBiComAsv { public: AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Or(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Or) @@ -6740,7 +6632,7 @@ public: class AstAnd final : public AstNodeBiComAsv { public: AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_And(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(And) @@ -6762,7 +6654,7 @@ public: class AstXor final : public AstNodeBiComAsv { public: AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Xor(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Xor) @@ -6784,7 +6676,7 @@ public: class AstEq final : public AstNodeBiCom { public: AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Eq(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Eq) @@ -6808,7 +6700,7 @@ public: class AstEqD final : public AstNodeBiCom { public: AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_EqD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqD) @@ -6832,7 +6724,7 @@ public: class AstEqN final : public AstNodeBiCom { public: AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_EqN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqN) @@ -6856,7 +6748,7 @@ public: class AstNeq final : public AstNodeBiCom { public: AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Neq(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Neq) @@ -6878,7 +6770,7 @@ public: class AstNeqD final : public AstNodeBiCom { public: AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_NeqD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqD) @@ -6902,7 +6794,7 @@ public: class AstNeqN final : public AstNodeBiCom { public: AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_NeqN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqN) @@ -6926,7 +6818,7 @@ public: class AstLt final : public AstNodeBiop { public: AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Lt(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Lt) @@ -6948,7 +6840,7 @@ public: class AstLtD final : public AstNodeBiop { public: AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LtD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtD) @@ -6972,7 +6864,7 @@ public: class AstLtS final : public AstNodeBiop { public: AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LtS(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtS) @@ -6995,7 +6887,7 @@ public: class AstLtN final : public AstNodeBiop { public: AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LtN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtN) @@ -7019,7 +6911,7 @@ public: class AstGt final : public AstNodeBiop { public: AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Gt(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Gt) @@ -7041,7 +6933,7 @@ public: class AstGtD final : public AstNodeBiop { public: AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GtD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtD) @@ -7065,7 +6957,7 @@ public: class AstGtS final : public AstNodeBiop { public: AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GtS(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtS) @@ -7088,7 +6980,7 @@ public: class AstGtN final : public AstNodeBiop { public: AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GtN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtN) @@ -7112,7 +7004,7 @@ public: class AstGte final : public AstNodeBiop { public: AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Gte(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Gte) @@ -7136,7 +7028,7 @@ public: class AstGteD final : public AstNodeBiop { public: AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GteD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteD) @@ -7160,7 +7052,7 @@ public: class AstGteS final : public AstNodeBiop { public: AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GteS(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteS) @@ -7183,7 +7075,7 @@ public: class AstGteN final : public AstNodeBiop { public: AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GteN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteN) @@ -7207,7 +7099,7 @@ public: class AstLte final : public AstNodeBiop { public: AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Lte(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(Lte) @@ -7231,7 +7123,7 @@ public: class AstLteD final : public AstNodeBiop { public: AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LteD(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteD) @@ -7255,7 +7147,7 @@ public: class AstLteS final : public AstNodeBiop { public: AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LteS(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteS) @@ -7278,7 +7170,7 @@ public: class AstLteN final : public AstNodeBiop { public: AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_LteN(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteN) @@ -7302,7 +7194,7 @@ public: class AstShiftL final : public AstNodeBiop { public: AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ShiftL(fl, lhsp, rhsp) { if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ShiftL) @@ -7326,7 +7218,7 @@ public: class AstShiftR final : public AstNodeBiop { public: AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ShiftR(fl, lhsp, rhsp) { if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(ShiftR) @@ -7353,7 +7245,7 @@ class AstShiftRS final : public AstNodeBiop { // Output data type's width determines which bit is used for sign extension public: AstShiftRS(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ShiftRS(fl, lhsp, rhsp) { // Important that widthMin be correct, as opExtend requires it after V3Expand if (setwidth) dtypeSetLogicSized(setwidth, VSigning::SIGNED); } @@ -7377,7 +7269,7 @@ public: class AstAdd final : public AstNodeBiComAsv { public: AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Add(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Add) @@ -7399,7 +7291,7 @@ public: class AstAddD final : public AstNodeBiComAsv { public: AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_AddD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(AddD) @@ -7423,7 +7315,7 @@ public: class AstSub final : public AstNodeBiop { public: AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Sub(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Sub) @@ -7445,7 +7337,7 @@ public: class AstSubD final : public AstNodeBiop { public: AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_SubD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(SubD) @@ -7469,7 +7361,7 @@ public: class AstMul final : public AstNodeBiComAsv { public: AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Mul(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Mul) @@ -7492,7 +7384,7 @@ public: class AstMulD final : public AstNodeBiComAsv { public: AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_MulD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(MulD) @@ -7516,7 +7408,7 @@ public: class AstMulS final : public AstNodeBiComAsv { public: AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_MulS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(MulS) @@ -7541,7 +7433,7 @@ public: class AstDiv final : public AstNodeBiop { public: AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Div(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Div) @@ -7563,7 +7455,7 @@ public: class AstDivD final : public AstNodeBiop { public: AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_DivD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(DivD) @@ -7587,7 +7479,7 @@ public: class AstDivS final : public AstNodeBiop { public: AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_DivS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(DivS) @@ -7610,7 +7502,7 @@ public: class AstModDiv final : public AstNodeBiop { public: AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ModDiv(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(ModDiv) @@ -7632,7 +7524,7 @@ public: class AstModDivS final : public AstNodeBiop { public: AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ModDivS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(ModDivS) @@ -7655,7 +7547,7 @@ public: class AstPow final : public AstNodeBiop { public: AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Pow(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(Pow) @@ -7678,7 +7570,7 @@ public: class AstPowD final : public AstNodeBiop { public: AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_PowD(fl, lhsp, rhsp) { dtypeSetDouble(); } ASTNODE_NODE_FUNCS(PowD) @@ -7701,7 +7593,7 @@ public: class AstPowSU final : public AstNodeBiop { public: AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_PowSU(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(PowSU) @@ -7727,7 +7619,7 @@ public: class AstPowSS final : public AstNodeBiop { public: AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_PowSS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(PowSS) @@ -7753,7 +7645,7 @@ public: class AstPowUS final : public AstNodeBiop { public: AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_PowUS(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(PowUS) @@ -7784,7 +7676,7 @@ class AstPreAdd final : public AstNodeTriop { // Children: thsp: tree with AstVarRef LValue that is stored after operation public: AstPreAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {} + : ASTGEN_SUPER_PreAdd(fl, lhsp, rhsp, thsp) {} ASTNODE_NODE_FUNCS(PreAdd) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override { @@ -7809,7 +7701,7 @@ class AstPreSub final : public AstNodeTriop { // Children: thsp: tree with AstVarRef LValue that is stored after operation public: AstPreSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {} + : ASTGEN_SUPER_PreSub(fl, lhsp, rhsp, thsp) {} ASTNODE_NODE_FUNCS(PreSub) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override { @@ -7834,7 +7726,7 @@ class AstPostAdd final : public AstNodeTriop { // Children: thsp: tree with AstVarRef LValue that is stored after operation public: AstPostAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {} + : ASTGEN_SUPER_PostAdd(fl, lhsp, rhsp, thsp) {} ASTNODE_NODE_FUNCS(PostAdd) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override { @@ -7859,7 +7751,7 @@ class AstPostSub final : public AstNodeTriop { // Children: thsp: tree with AstVarRef LValue that is stored after operation public: AstPostSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* thsp) - : ASTGEN_SUPER(fl, lhsp, rhsp, thsp) {} + : ASTGEN_SUPER_PostSub(fl, lhsp, rhsp, thsp) {} ASTNODE_NODE_FUNCS(PostSub) virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, const V3Number& ths) override { @@ -7879,7 +7771,7 @@ public: class AstEqCase final : public AstNodeBiCom { public: AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_EqCase(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqCase) @@ -7901,7 +7793,7 @@ public: class AstNeqCase final : public AstNodeBiCom { public: AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_NeqCase(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqCase) @@ -7924,7 +7816,7 @@ class AstEqWild final : public AstNodeBiop { // Note wildcard operator rhs differs from lhs public: AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_EqWild(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqWild) @@ -7948,7 +7840,7 @@ public: class AstNeqWild final : public AstNodeBiop { public: AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_NeqWild(fl, lhsp, rhsp) { dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqWild) @@ -7971,7 +7863,7 @@ class AstConcat final : public AstNodeBiop { // If you're looking for {#{}}, see AstReplicate public: AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Concat(fl, lhsp, rhsp) { if (lhsp->dtypep() && rhsp->dtypep()) { dtypeSetLogicSized(lhsp->dtypep()->width() + rhsp->dtypep()->width(), VSigning::UNSIGNED); @@ -7997,7 +7889,7 @@ class AstConcatN final : public AstNodeBiop { // String concatenate public: AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ConcatN(fl, lhsp, rhsp) { dtypeSetString(); } ASTNODE_NODE_FUNCS(ConcatN) @@ -8022,7 +7914,7 @@ class AstReplicate final : public AstNodeBiop { // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() public: AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_Replicate(fl, lhsp, rhsp) { if (lhsp) { if (const AstConst* constp = VN_CAST(rhsp, Const)) { dtypeSetLogicSized(lhsp->width() * constp->toUInt(), VSigning::UNSIGNED); @@ -8051,7 +7943,7 @@ class AstReplicateN final : public AstNodeBiop { // String replicate public: AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_ReplicateN(fl, lhsp, rhsp) { dtypeSetString(); } AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount) @@ -8077,7 +7969,7 @@ class AstStreamL final : public AstNodeStream { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() public: AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_StreamL(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(StreamL) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstStreamL(this->fileline(), lhsp, rhsp); @@ -8098,7 +7990,7 @@ class AstStreamR final : public AstNodeStream { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() public: AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_StreamR(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(StreamR) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstStreamR(this->fileline(), lhsp, rhsp); @@ -8121,7 +8013,7 @@ class AstBufIf1 final : public AstNodeBiop { // bit enables respective rhsp bit public: AstBufIf1(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_BufIf1(fl, lhsp, rhsp) { dtypeFrom(lhsp); } ASTNODE_NODE_FUNCS(BufIf1) @@ -8143,7 +8035,7 @@ public: class AstFGetS final : public AstNodeBiop { public: AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_FGetS(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(FGetS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstFGetS(this->fileline(), lhsp, rhsp); @@ -8184,7 +8076,7 @@ public: class AstAtan2D final : public AstNodeSystemBiop { public: AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_Atan2D(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(Atan2D) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstAtan2D(this->fileline(), lhsp, rhsp); @@ -8199,7 +8091,7 @@ public: class AstHypotD final : public AstNodeSystemBiop { public: AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) {} + : ASTGEN_SUPER_HypotD(fl, lhsp, rhsp) {} ASTNODE_NODE_FUNCS(HypotD) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { return new AstHypotD(this->fileline(), lhsp, rhsp); @@ -8215,7 +8107,7 @@ class AstPutcN final : public AstNodeTriop { // Verilog string.putc() public: AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER(fl, lhsp, rhsp, ths) { + : ASTGEN_SUPER_PutcN(fl, lhsp, rhsp, ths) { dtypeSetString(); } ASTNODE_NODE_FUNCS(PutcN) @@ -8241,7 +8133,7 @@ class AstGetcN final : public AstNodeBiop { // Verilog string.getc() public: AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GetcN(fl, lhsp, rhsp) { dtypeSetBitSized(8, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(GetcN) @@ -8268,7 +8160,7 @@ class AstGetcRefN final : public AstNodeBiop { // Spec says is of type byte (not string of single character) public: AstGetcRefN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) - : ASTGEN_SUPER(fl, lhsp, rhsp) { + : ASTGEN_SUPER_GetcRefN(fl, lhsp, rhsp) { dtypeSetBitSized(8, VSigning::UNSIGNED); } ASTNODE_NODE_FUNCS(GetcRefN) @@ -8293,7 +8185,7 @@ class AstSubstrN final : public AstNodeTriop { // Verilog string.substr() public: AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) - : ASTGEN_SUPER(fl, lhsp, rhsp, ths) { + : ASTGEN_SUPER_SubstrN(fl, lhsp, rhsp, ths) { dtypeSetString(); } ASTNODE_NODE_FUNCS(SubstrN) @@ -8321,7 +8213,7 @@ private: bool m_ignoreCase; // True for str.icompare() public: AstCompareNN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, bool ignoreCase) - : ASTGEN_SUPER(fl, lhsp, rhsp) + : ASTGEN_SUPER_CompareNN(fl, lhsp, rhsp) , m_ignoreCase{ignoreCase} { dtypeSetUInt32(); } @@ -8354,7 +8246,7 @@ class AstFell final : public AstNodeMath { // Children: expression public: AstFell(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Fell(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Fell) @@ -8366,7 +8258,6 @@ public: AstNode* exprp() const { return op1p(); } // op1 = expression AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8376,7 +8267,7 @@ class AstPast final : public AstNodeMath { // Children: expression public: AstPast(FileLine* fl, AstNode* exprp, AstNode* ticksp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Past(fl) { addOp1p(exprp); addNOp2p(ticksp); } @@ -8390,7 +8281,6 @@ public: AstNode* ticksp() const { return op2p(); } // op2 = ticks or nullptr means 1 AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8400,7 +8290,7 @@ class AstRose final : public AstNodeMath { // Children: expression public: AstRose(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Rose(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Rose) @@ -8412,7 +8302,6 @@ public: AstNode* exprp() const { return op1p(); } // op1 = expression AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8422,7 +8311,7 @@ class AstSampled final : public AstNodeMath { // Children: expression public: AstSampled(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Sampled(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Sampled) @@ -8432,7 +8321,6 @@ public: virtual bool cleanOut() const override { V3ERROR_NA_RETURN(""); } virtual int instrCount() const override { return 0; } AstNode* exprp() const { return op1p(); } // op1 = expression - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8442,7 +8330,7 @@ class AstStable final : public AstNodeMath { // Children: expression public: AstStable(FileLine* fl, AstNode* exprp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Stable(fl) { addOp1p(exprp); } ASTNODE_NODE_FUNCS(Stable) @@ -8454,7 +8342,6 @@ public: AstNode* exprp() const { return op1p(); } // op1 = expression AstSenTree* sentreep() const { return VN_CAST(op2p(), SenTree); } // op2 = clock domain void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8464,7 +8351,7 @@ class AstPattern final : public AstNodeMath { // Children: expression, AstPattern, AstPatReplicate public: AstPattern(FileLine* fl, AstNode* itemsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Pattern(fl) { addNOp2p(itemsp); } ASTNODE_NODE_FUNCS(Pattern) @@ -8489,7 +8376,7 @@ private: public: AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_PatMember(fl) { addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); } ASTNODE_NODE_FUNCS(PatMember) @@ -8513,7 +8400,7 @@ class AstImplication final : public AstNodeMath { // Children: expression public: AstImplication(FileLine* fl, AstNode* lhs, AstNode* rhs) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Implication(fl) { setOp1p(lhs); setOp2p(rhs); } @@ -8529,7 +8416,6 @@ public: void rhsp(AstNode* nodep) { return setOp2p(nodep); } AstSenTree* sentreep() const { return VN_CAST(op4p(), SenTree); } // op4 = clock domain void sentreep(AstSenTree* sentreep) { addOp4p(sentreep); } // op4 = clock domain - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8542,7 +8428,7 @@ class AstClocking final : public AstNode { // Children: Assertions public: AstClocking(FileLine* fl, AstSenItem* sensesp, AstNode* bodysp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_Clocking(fl) { addOp1p(sensesp); addNOp2p(bodysp); } @@ -8561,7 +8447,7 @@ class AstPropClocked final : public AstNode { // Children: SENITEM, Properties public: AstPropClocked(FileLine* fl, AstSenItem* sensesp, AstNode* disablep, AstNode* propp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_PropClocked(fl) { addNOp1p(sensesp); addNOp2p(disablep); addOp3p(propp); @@ -8593,7 +8479,6 @@ public: } ASTNODE_BASE_FUNCS(NodeCoverOrAssert) virtual string name() const override { return m_name; } // * = Var name - virtual V3Hash sameHash() const override { return V3Hash(name()); } virtual bool same(const AstNode* samep) const override { return samep->name() == name(); } virtual void name(const string& name) override { m_name = name; } virtual void dump(std::ostream& str = std::cout) const override; @@ -8609,7 +8494,7 @@ public: ASTNODE_NODE_FUNCS(Assert) AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, const string& name = "") - : ASTGEN_SUPER(fl, propp, passsp, immediate, name) { + : ASTGEN_SUPER_Assert(fl, propp, passsp, immediate, name) { addNOp3p(failsp); } AstNode* failsp() const { return op3p(); } // op3 = if assertion fails @@ -8621,7 +8506,7 @@ public: ASTNODE_NODE_FUNCS(AssertIntrinsic) AstAssertIntrinsic(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, const string& name = "") - : ASTGEN_SUPER(fl, propp, passsp, immediate, name) { + : ASTGEN_SUPER_AssertIntrinsic(fl, propp, passsp, immediate, name) { addNOp3p(failsp); } AstNode* failsp() const { return op3p(); } // op3 = if assertion fails @@ -8632,7 +8517,7 @@ public: ASTNODE_NODE_FUNCS(Cover) AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, bool immediate, const string& name = "") - : ASTGEN_SUPER(fl, propp, stmtsp, immediate, name) {} + : ASTGEN_SUPER_Cover(fl, propp, stmtsp, immediate, name) {} AstNode* coverincp() const { return op3p(); } // op3 = coverage node void coverincp(AstCoverInc* nodep) { addOp3p(nodep); } // op3 = coverage node virtual bool immediate() const { return false; } @@ -8642,7 +8527,7 @@ class AstRestrict final : public AstNodeCoverOrAssert { public: ASTNODE_NODE_FUNCS(Restrict) AstRestrict(FileLine* fl, AstNode* propp) - : ASTGEN_SUPER(fl, propp, nullptr, false, "") {} + : ASTGEN_SUPER_Restrict(fl, propp, nullptr, false, "") {} }; //====================================================================== @@ -8663,7 +8548,7 @@ public: class AstText final : public AstNodeSimpleText { public: AstText(FileLine* fl, const string& textp, bool tracking = false) - : ASTGEN_SUPER(fl, textp, tracking) {} + : ASTGEN_SUPER_Text(fl, textp, tracking) {} ASTNODE_NODE_FUNCS(Text) }; @@ -8673,7 +8558,7 @@ private: public: explicit AstTextBlock(FileLine* fl, const string& textp = "", bool tracking = false, bool commas = false) - : ASTGEN_SUPER(fl, textp, tracking) + : ASTGEN_SUPER_TextBlock(fl, textp, tracking) , m_commas(commas) {} ASTNODE_NODE_FUNCS(TextBlock) void commas(bool flag) { m_commas = flag; } @@ -8688,7 +8573,7 @@ public: class AstScCtor final : public AstNodeText { public: AstScCtor(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScCtor(fl, textp) {} ASTNODE_NODE_FUNCS(ScCtor) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8697,7 +8582,7 @@ public: class AstScDtor final : public AstNodeText { public: AstScDtor(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScDtor(fl, textp) {} ASTNODE_NODE_FUNCS(ScDtor) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8706,7 +8591,7 @@ public: class AstScHdr final : public AstNodeText { public: AstScHdr(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScHdr(fl, textp) {} ASTNODE_NODE_FUNCS(ScHdr) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8715,7 +8600,7 @@ public: class AstScImp final : public AstNodeText { public: AstScImp(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScImp(fl, textp) {} ASTNODE_NODE_FUNCS(ScImp) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8724,7 +8609,7 @@ public: class AstScImpHdr final : public AstNodeText { public: AstScImpHdr(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScImpHdr(fl, textp) {} ASTNODE_NODE_FUNCS(ScImpHdr) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8733,7 +8618,7 @@ public: class AstScInt final : public AstNodeText { public: AstScInt(FileLine* fl, const string& textp) - : ASTGEN_SUPER(fl, textp) {} + : ASTGEN_SUPER_ScInt(fl, textp) {} ASTNODE_NODE_FUNCS(ScInt) virtual bool isPure() const override { return false; } // SPECIAL: User may order w/other sigs virtual bool isOutputter() const override { return true; } @@ -8743,7 +8628,7 @@ class AstUCStmt final : public AstNodeStmt { // User $c statement public: AstUCStmt(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_UCStmt(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(UCStmt) @@ -8752,7 +8637,6 @@ public: virtual bool isPredictOptimizable() const override { return false; } virtual bool isPure() const override { return false; } virtual bool isOutputter() const override { return true; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; @@ -8773,7 +8657,6 @@ public: ASTNODE_BASE_FUNCS(NodeFile) virtual void dump(std::ostream& str) const override; virtual string name() const override { return m_name; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void tblockp(AstTextBlock* tblockp) { setOp1p(tblockp); } AstTextBlock* tblockp() { return VN_CAST(op1p(), TextBlock); } @@ -8787,7 +8670,7 @@ class AstVFile final : public AstNodeFile { // Parents: NETLIST public: AstVFile(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) {} + : ASTGEN_SUPER_VFile(fl, name) {} ASTNODE_NODE_FUNCS(VFile) virtual void dump(std::ostream& str = std::cout) const override; }; @@ -8804,7 +8687,7 @@ private: bool m_support : 1; ///< Support file (non systemc) public: AstCFile(FileLine* fl, const string& name) - : ASTGEN_SUPER(fl, name) + : ASTGEN_SUPER_CFile(fl, name) , m_slow{false} , m_source{false} , m_support{false} {} @@ -8853,7 +8736,7 @@ private: bool m_dpiImportWrapper : 1; // Wrapper from dpi import public: AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "") - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CFunc(fl) { m_funcType = AstCFuncType::FT_NORMAL; m_isConst = VBoolOrUnknown::BU_UNKNOWN; // Unknown until analyzed m_isStatic = VBoolOrUnknown::BU_UNKNOWN; // Unknown until see where thisp needed @@ -8887,7 +8770,6 @@ public: } virtual bool maybePointedTo() const override { return true; } virtual void dump(std::ostream& str = std::cout) const override; - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { const AstCFunc* asamep = static_cast(samep); return ((funcType() == asamep->funcType()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) @@ -8976,11 +8858,7 @@ class AstCCall final : public AstNodeCCall { // Children: Args to the function public: AstCCall(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER(fl, funcp, argsp) {} - // Replacement form for V3Combine - // Note this removes old attachments from the oldp - AstCCall(AstCCall* oldp, AstCFunc* funcp) - : ASTGEN_SUPER(oldp, funcp) {} + : ASTGEN_SUPER_CCall(fl, funcp, argsp) {} ASTNODE_NODE_FUNCS(CCall) }; @@ -8990,7 +8868,7 @@ class AstCMethodCall final : public AstNodeCCall { // Children: Args to the function public: AstCMethodCall(FileLine* fl, AstNode* fromp, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER(fl, funcp, argsp) { + : ASTGEN_SUPER_CMethodCall(fl, funcp, argsp) { setOp1p(fromp); } ASTNODE_NODE_FUNCS(CMethodCall) @@ -9011,13 +8889,9 @@ class AstCNew final : public AstNodeCCall { // Children: Args to the function public: AstCNew(FileLine* fl, AstCFunc* funcp, AstNode* argsp = nullptr) - : ASTGEN_SUPER(fl, funcp, argsp) { + : ASTGEN_SUPER_CNew(fl, funcp, argsp) { statement(false); } - // Replacement form for V3Combine - // Note this removes old attachments from the oldp - AstCNew(AstCCall* oldp, AstCFunc* funcp) - : ASTGEN_SUPER(oldp, funcp) {} virtual bool hasDType() const override { return true; } ASTNODE_NODE_FUNCS(CNew) }; @@ -9028,12 +8902,11 @@ class AstCReturn final : public AstNodeStmt { // Children: Math public: AstCReturn(FileLine* fl, AstNode* lhsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CReturn(fl) { setOp1p(lhsp); } ASTNODE_NODE_FUNCS(CReturn) virtual int instrCount() const override { return widthInstrs(); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } // AstNode* lhsp() const { return op1p(); } @@ -9046,14 +8919,14 @@ private: public: // Emit C textual math function (like AstUCFunc) AstCMath(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CMath(fl) , m_cleanOut{true} , m_pure{false} { addOp1p(exprsp); dtypeFrom(exprsp); } AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut = true) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CMath(fl) , m_cleanOut{cleanOut} , m_pure{true} { addNOp1p(new AstText(fl, textStmt, true)); @@ -9065,7 +8938,6 @@ public: virtual bool cleanOut() const override { return m_cleanOut; } virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void addBodysp(AstNode* nodep) { addNOp1p(nodep); } AstNode* bodysp() const { return op1p(); } // op1 = expressions to print @@ -9077,13 +8949,12 @@ class AstCReset final : public AstNodeStmt { // Reset variable at startup public: AstCReset(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CReset(fl) { addNOp1p(exprsp); } ASTNODE_NODE_FUNCS(CReset) virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } AstVarRef* varrefp() const { return VN_CAST(op1p(), VarRef); } // op1 = varref to reset }; @@ -9092,17 +8963,16 @@ class AstCStmt final : public AstNodeStmt { // Emit C statement public: AstCStmt(FileLine* fl, AstNode* exprsp) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CStmt(fl) { addNOp1p(exprsp); } AstCStmt(FileLine* fl, const string& textStmt) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_CStmt(fl) { addNOp1p(new AstText(fl, textStmt, true)); } ASTNODE_NODE_FUNCS(CStmt) virtual bool isGateOptimizable() const override { return false; } virtual bool isPredictOptimizable() const override { return false; } - virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } void addBodysp(AstNode* nodep) { addNOp1p(nodep); } AstNode* bodysp() const { return op1p(); } // op1 = expressions to print @@ -9117,7 +8987,7 @@ private: public: AstCUse(FileLine* fl, VUseType useType, const string& name) - : ASTGEN_SUPER(fl) + : ASTGEN_SUPER_CUse(fl) , m_useType{useType} , m_name{name} {} ASTNODE_NODE_FUNCS(CUse) @@ -9134,7 +9004,7 @@ private: public: explicit AstMTaskBody(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_MTaskBody(fl) {} ASTNODE_NODE_FUNCS(MTaskBody); virtual const char* broken() const override { BROKEN_RTN(!m_execMTaskp); @@ -9175,7 +9045,7 @@ class AstSplitPlaceholder final : public AstNode { public: // Dummy node used within V3Split; never exists outside of V3Split. explicit AstSplitPlaceholder(FileLine* fl) - : ASTGEN_SUPER(fl) {} + : ASTGEN_SUPER_SplitPlaceholder(fl) {} ASTNODE_NODE_FUNCS(SplitPlaceholder) }; @@ -9194,7 +9064,7 @@ class AstTypeTable final : public AstNode { public: explicit AstTypeTable(FileLine* fl) - : ASTGEN_SUPER(fl) { + : ASTGEN_SUPER_TypeTable(fl) { for (int i = 0; i < AstBasicDTypeKwd::_ENUM_MAX; ++i) m_basicps[i] = nullptr; } ASTNODE_NODE_FUNCS(TypeTable) @@ -9230,7 +9100,7 @@ private: bool m_timescaleSpecified = false; // Input HDL specified timescale public: AstNetlist() - : ASTGEN_SUPER(new FileLine(FileLine::builtInFilename())) {} + : ASTGEN_SUPER_Netlist(new FileLine(FileLine::builtInFilename())) {} ASTNODE_NODE_FUNCS(Netlist) virtual const char* broken() const override { BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); @@ -9285,6 +9155,6 @@ public: //###################################################################### -#undef ASTGEN_SUPER +#include "V3AstInlines.h" #endif // Guard diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 2aa30b2f7..b8b989aeb 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -32,63 +32,99 @@ #include "V3CCtors.h" #include -#include +#include + +class VCtorType final { +public: + enum en : uint8_t { MODULE, CLASS, COVERAGE }; -class V3CCtorsVisitor final { private: - string m_basename; - string m_argsp; - string m_callargsp; - AstNodeModule* m_modp; // Current module - AstCFunc* m_tlFuncp; // Top level function being built - AstCFunc* m_funcp; // Current function + enum en m_e; + +public: + // cppcheck-suppress noExplicitConstructor + inline VCtorType(en _e) + : m_e{_e} {} + bool isClass() const { return m_e == CLASS; } + bool isCoverage() const { return m_e == COVERAGE; } +}; + +class V3CCtorsBuilder final { +private: + AstNodeModule* const m_modp; // Current module/class + const string m_basename; + const VCtorType m_type; // What kind of constructor are we creating + std::list m_newFunctions; // Created functions, latest is at back int m_numStmts = 0; // Number of statements output - int m_funcNum = 0; // Function number being built + + AstCFunc* makeNewFunc() { + const int funcNum = m_newFunctions.size(); + const string funcName = m_basename + "_" + cvtToStr(funcNum); + AstCFunc* const funcp = new AstCFunc(m_modp->fileline(), funcName, nullptr, "void"); + funcp->isStatic(!m_type.isClass()); // Class constructors are non static + funcp->declPrivate(true); + funcp->slow(!m_type.isClass()); // Only classes construct on fast path + string preventUnusedStmt; + if (m_type.isClass()) { + funcp->argTypes(EmitCBaseVisitor::symClassVar()); + preventUnusedStmt = "if (false && vlSymsp) {}"; + } else if (m_type.isCoverage()) { + funcp->argTypes(EmitCBaseVisitor::prefixNameProtect(m_modp) + "* self, " + + EmitCBaseVisitor::symClassVar() + ", bool first"); + preventUnusedStmt = "if (false && self && vlSymsp && first) {}"; + } else { // Module + funcp->argTypes(EmitCBaseVisitor::prefixNameProtect(m_modp) + "* self"); + preventUnusedStmt = "if (false && self) {}"; + } + preventUnusedStmt += " // Prevent unused\n"; + funcp->addStmtsp(new AstCStmt(m_modp->fileline(), preventUnusedStmt)); + m_modp->addStmtp(funcp); + m_numStmts = 0; + return funcp; + } public: void add(AstNode* nodep) { - if (v3Global.opt.outputSplitCFuncs() && v3Global.opt.outputSplitCFuncs() < m_numStmts) { - m_funcp = nullptr; + if (v3Global.opt.outputSplitCFuncs() && m_numStmts > v3Global.opt.outputSplitCFuncs()) { + m_newFunctions.push_back(makeNewFunc()); } - if (!m_funcp) { - m_funcp = new AstCFunc(m_modp->fileline(), m_basename + "_" + cvtToStr(++m_funcNum), - nullptr, "void"); - m_funcp->isStatic(false); - m_funcp->declPrivate(true); - m_funcp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path - m_funcp->argTypes(m_argsp); - m_modp->addStmtp(m_funcp); - - // Add a top call to it - AstCCall* callp = new AstCCall(m_modp->fileline(), m_funcp); - callp->argTypes(m_callargsp); - - m_tlFuncp->addStmtsp(callp); - m_numStmts = 0; - } - m_funcp->addStmtsp(nodep); + m_newFunctions.back()->addStmtsp(nodep); m_numStmts += 1; } - V3CCtorsVisitor(AstNodeModule* nodep, const string& basename, const string& argsp = "", - const string& callargsp = "", const string& stmt = "") { - m_basename = basename; - m_argsp = argsp; - m_callargsp = callargsp; - m_modp = nodep; - m_tlFuncp = new AstCFunc(nodep->fileline(), basename, nullptr, "void"); - m_tlFuncp->declPrivate(true); - m_tlFuncp->isStatic(false); - m_tlFuncp->slow(!VN_IS(m_modp, Class)); // Only classes construct on fast path - m_tlFuncp->argTypes(m_argsp); - if (stmt != "") m_tlFuncp->addStmtsp(new AstCStmt(nodep->fileline(), stmt)); - m_funcp = m_tlFuncp; - m_modp->addStmtp(m_tlFuncp); + V3CCtorsBuilder(AstNodeModule* nodep, const string& basename, VCtorType type) + : m_modp(nodep) + , m_basename{basename} + , m_type(type) { + // Note: The constructor is always called, even if empty, so we must always create at least + // one. + m_newFunctions.push_back(makeNewFunc()); } - ~V3CCtorsVisitor() = default; + + ~V3CCtorsBuilder() { + if (m_newFunctions.size() == 1) { + // No split was necessary, rename the one function to the basename + m_newFunctions.front()->name(m_basename); + } else { + // Split was necessary, create root function and call all others from that + AstCFunc* const rootFuncp = makeNewFunc(); + rootFuncp->name(m_basename); + for (AstCFunc* const funcp : m_newFunctions) { + AstCCall* const callp = new AstCCall(m_modp->fileline(), funcp); + if (m_type.isClass()) { + callp->argTypes("vlSymsp"); + } else if (m_type.isCoverage()) { + callp->argTypes("self, vlSymsp, first"); + } else { // Module + callp->argTypes("self"); + } + rootFuncp->addStmtsp(callp); + } + } + }; private: - VL_UNCOPYABLE(V3CCtorsVisitor); + VL_UNCOPYABLE(V3CCtorsBuilder); }; //###################################################################### @@ -140,32 +176,24 @@ void V3CCtors::cctorsAll() { modp = VN_CAST(modp->nextp(), NodeModule)) { // Process each module in turn { - V3CCtorsVisitor var_reset( - modp, "_ctor_var_reset", - (VN_IS(modp, Class) ? EmitCBaseVisitor::symClassVar() : ""), - (VN_IS(modp, Class) ? "vlSymsp" : ""), - (VN_IS(modp, Class) ? "if (false && vlSymsp) {} // Prevent unused\n" : "")); + V3CCtorsBuilder var_reset(modp, "_ctor_var_reset", + VN_IS(modp, Class) ? VCtorType::CLASS : VCtorType::MODULE); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { - if (AstVar* varp = VN_CAST(np, Var)) { + if (AstVar* const varp = VN_CAST(np, Var)) { if (!varp->isIfaceParent() && !varp->isIfaceRef() && !varp->noReset()) { - var_reset.add( - new AstCReset(varp->fileline(), - new AstVarRef(varp->fileline(), varp, VAccess::WRITE))); + const auto vrefp = new AstVarRef(varp->fileline(), varp, VAccess::WRITE); + var_reset.add(new AstCReset(varp->fileline(), vrefp)); } } } } if (v3Global.opt.coverage()) { - V3CCtorsVisitor configure_coverage( - modp, "_configure_coverage", EmitCBaseVisitor::symClassVar() + ", bool first", - "vlSymsp, first", "if (false && vlSymsp && first) {} // Prevent unused\n"); + V3CCtorsBuilder configure_coverage(modp, "_configure_coverage", VCtorType::COVERAGE); for (AstNode* np = modp->stmtsp(); np; np = np->nextp()) { - if (AstCoverDecl* coverp = VN_CAST(np, CoverDecl)) { - AstNode* backp = coverp->backp(); - coverp->unlinkFrBack(); - configure_coverage.add(coverp); - np = backp; + if (AstCoverDecl* const coverp = VN_CAST(np, CoverDecl)) { + np = coverp->backp(); + configure_coverage.add(coverp->unlinkFrBack()); } } } diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index eb5cd526c..05620b081 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -301,20 +301,6 @@ private: } VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); } - virtual void visit(AstAlwaysPost* nodep) override { - if (AstNode* stmtsp = nodep->bodysp()) { - stmtsp->unlinkFrBackWithNext(); - nodep->addNextHere(stmtsp); - } - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } - virtual void visit(AstAlwaysPostponed* nodep) override { - if (AstNode* stmtsp = nodep->bodysp()) { - stmtsp->unlinkFrBackWithNext(); - nodep->addNextHere(stmtsp); - } - VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); - } virtual void visit(AstCoverToggle* nodep) override { // nodep->dumpTree(cout, "ct:"); // COVERTOGGLE(INC, ORIG, CHANGE) -> diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index bb9c081aa..b859b455c 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -15,19 +15,8 @@ //************************************************************************* // V3Combine's Transformations: // -// For every function that we spit out -// Examine code to find largest common blocks -// Hash each node depth first -// Hash includes varp name and operator type, and constants -// Form lookup table based on hash of each statement w/ nodep and next nodep -// GO through table -// Lookup in hash, while next of each statement match, grow that common block -// Foreach common block -// If common block large enough (> 20 statements) & used 2x or more -// Make new function -// Move common block to function -// Replace each common block ref with funccall -// +// Combine identical CFuncs by retaining only a single copy +// Also drop empty CFuncs //************************************************************************* #include "config_build.h" @@ -35,7 +24,7 @@ #include "V3Global.h" #include "V3Combine.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include "V3Stats.h" #include "V3Ast.h" @@ -45,12 +34,6 @@ //###################################################################### -#ifdef VL_COMBINE_STATEMENTS -constexpr int COMBINE_MIN_STATEMENTS = 50; // Min # of statements to be worth making a function -#endif - -//###################################################################### - class CombBaseVisitor VL_NOT_FINAL : public AstNVisitor { protected: // STATE @@ -67,8 +50,7 @@ class CombCallVisitor final : CombBaseVisitor { // Find all CCALLS of each CFUNC, so that we can later rename them private: // NODE STATE - using CallMmap = std::multimap; - CallMmap m_callMmap; // Associative array of {function}{call} + std::multimap m_callMmap; // Associative array of {function}{call} // METHODS public: void replaceFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) { @@ -81,44 +63,32 @@ public: // Note: m_callMmap modified in loop, so not using equal_range. for (auto it = m_callMmap.find(oldfuncp); it != m_callMmap.end(); it = m_callMmap.find(oldfuncp)) { - AstCCall* callp = it->second; - if (!callp->user3()) { // !already done - UINFO(4, " Called " << callp << endl); - UASSERT_OBJ(callp->funcp() == oldfuncp, callp, - "Call list broken, points to call w/different func"); - if (newfuncp) { - AstCCall* newp = new AstCCall(callp, newfuncp); - // Special new AstCCall form above transfers children of callp to newfuncp - callp->replaceWith(newp); - addCall(newp); // Fix the table - } else { // Just deleting empty function - callp->unlinkFrBack(); - } - callp->user3(true); // Dead now - VL_DO_DANGLING(pushDeletep(callp), callp); + AstCCall* const oldp = it->second; + UINFO(4, " Called " << oldp << endl); + UASSERT_OBJ(oldp->funcp() == oldfuncp, oldp, + "Call list broken, points to call w/different func"); + if (newfuncp) { + // Replace call to oldfuncp with call to newfuncp + AstNode* const argsp + = oldp->argsp() ? oldp->argsp()->unlinkFrBackWithNext() : nullptr; + AstCCall* const newp = new AstCCall(oldp->fileline(), newfuncp, argsp); + newp->hiernameToProt(oldp->hiernameToProt()); + newp->hiernameToUnprot(oldp->hiernameToUnprot()); + newp->argTypes(oldp->argTypes()); + addCall(newp); // Fix the table, in case the newfuncp itself gets replaced + oldp->replaceWith(newp); + } else { + // Just deleting empty function + oldp->unlinkFrBack(); } - // It is safe to unconditionally remove this entry here as the above - // 'if' would never be entered again for this entry (we set user3). - // The only other place where m_callMmap is looked up is deleteCall - // below, but that is only ever called straight after an addCall - // of the node being deleted, so it won't miss this entry. - m_callMmap.erase(it); // Fix the table + VL_DO_DANGLING(pushDeletep(oldp), oldp); + m_callMmap.erase(it); // Fix the table, This call has been replaced } } // METHODS - void addCall(AstCCall* nodep) { m_callMmap.emplace(nodep->funcp(), nodep); } - void deleteCall(AstCCall* nodep) { - std::pair eqrange - = m_callMmap.equal_range(nodep->funcp()); - for (auto nextit = eqrange.first; nextit != eqrange.second;) { - const auto eqit = nextit++; - AstCCall* callp = eqit->second; - if (callp == nodep) { - m_callMmap.erase(eqit); - return; - } - } - nodep->v3fatalSrc("deleteCall node not found in table"); + void addCall(AstCCall* nodep) { + if (nodep->funcp()->dontCombine()) return; + m_callMmap.emplace(nodep->funcp(), nodep); } private: @@ -136,26 +106,6 @@ public: void main(AstNetlist* nodep) { iterate(nodep); } }; -//###################################################################### -// Combine marking function - -class CombMarkVisitor final : CombBaseVisitor { - // Mark all nodes under specified one. -private: - // OUTPUT: - // AstNode::user3() -> bool. True to indicate duplicated - // VISITORS - virtual void visit(AstNode* nodep) override { - nodep->user3(true); - iterateChildren(nodep); - } - -public: - // CONSTRUCTORS - explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~CombMarkVisitor() override = default; -}; - //###################################################################### // Combine state, as a visitor of each AstNode @@ -163,312 +113,100 @@ class CombineVisitor final : CombBaseVisitor { private: // NODE STATE // Entire netlist: - // AstNodeStmt::user() -> bool. True if iterated already - // AstCFunc::user3p() -> AstCFunc*, If set, replace ccalls to this func with new func - // AstNodeStmt::user3() -> AstNode*. True if to ignore this cell - // AstNodeStmt::user4() -> V3Hashed::V3Hash. Hash value of this node (hash of 0 is - // illegal) - AstUser1InUse m_inuser1; - AstUser3InUse m_inuser3; - // AstUser4InUse part of V3Hashed + AstUser3InUse m_user3InUse; // Marks replaced AstCFuncs + // AstUser4InUse part of V3Hasher in V3DupFinder // STATE - enum CombineState : uint8_t { STATE_IDLE, STATE_HASH, STATE_DUP }; - VDouble0 m_statCombs; // Statistic tracking - CombineState m_state = STATE_IDLE; // Major state - AstNodeModule* m_modp = nullptr; // Current module - AstCFunc* m_cfuncp = nullptr; // Current function + VDouble0 m_cfuncsCombined; // Statistic tracking CombCallVisitor m_call; // Tracking of function call users - int m_modNFuncs = 0; // Number of functions made -#ifdef VL_COMBINE_STATEMENTS - AstNode* m_walkLast1p = nullptr; // Final node that is the same in duplicate list -#endif - AstNode* m_walkLast2p = nullptr; // Final node that is the same in duplicate list - V3Hashed m_hashed; // Hash for every node in module + V3DupFinder m_dupFinder; // Duplicate finder for CFuncs in module // METHODS - void hashStatement(AstNode* nodep) { - // Compute hash on entire tree of this statement - m_hashed.hashAndInsert(nodep); - // UINFO(9, " stmthash " << hex << nodep->user4() << " " << nodep << endl); - } -#ifdef VL_COMBINE_STATEMENTS - void hashFunctions(AstCFunc* nodep) { - // Compute hash of all statement trees in the function - VL_RESTORER(m_state); - { - m_state = STATE_HASH; - iterate(nodep); - } - } -#endif void walkEmptyFuncs() { - for (const auto& itr : m_hashed) { - AstNode* node1p = itr.second; - AstCFunc* oldfuncp = VN_CAST(node1p, CFunc); - if (oldfuncp && oldfuncp->emptyBody() && !oldfuncp->dontCombine()) { - UINFO(5, " EmptyFunc " << std::hex << V3Hash(oldfuncp->user4p()) << " " - << oldfuncp << endl); - // Mark user3p on entire old tree, so we don't process it more - CombMarkVisitor visitor(oldfuncp); - m_call.replaceFunc(oldfuncp, nullptr); - oldfuncp->unlinkFrBack(); - VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); - } + for (const auto& itr : m_dupFinder) { + AstCFunc* const oldfuncp = VN_CAST(itr.second, CFunc); + UASSERT_OBJ(oldfuncp, itr.second, "Not a CFunc in hash"); + if (!oldfuncp->emptyBody()) continue; + UASSERT_OBJ(!oldfuncp->dontCombine(), oldfuncp, + "dontCombine function should not be in hash"); + + // Remove calls to empty function + UASSERT_OBJ(!oldfuncp->user3(), oldfuncp, "Should not be processed yet"); + UINFO(5, " Drop empty CFunc " << itr.first << " " << oldfuncp << endl); + oldfuncp->user3SetOnce(); // Mark replaced + m_call.replaceFunc(oldfuncp, nullptr); + oldfuncp->unlinkFrBack(); + VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); } } + void walkDupFuncs() { // Do non-slow first as then favors naming functions based on fast name - for (int slow = 0; slow < 2; ++slow) { - for (V3Hashed::iterator it = m_hashed.begin(); it != m_hashed.end(); ++it) { - AstNode* node1p = it->second; - AstCFunc* cfunc1p = VN_CAST(node1p, CFunc); - if (!cfunc1p) continue; - // cppcheck-suppress compareBoolExpressionWithInt - if (cfunc1p->slow() != slow) continue; - V3Hash hashval = it->first; - UASSERT_OBJ(!hashval.isIllegal(), node1p, "Illegal (unhashed) nodes"); - for (V3Hashed::iterator eqit = it; eqit != m_hashed.end(); ++eqit) { - AstNode* node2p = eqit->second; - if (!(eqit->first == hashval)) break; - if (node1p == node2p) continue; // Identical iterator - if (node1p->user3p() || node2p->user3p()) continue; // Already merged - if (node1p->sameTree(node2p)) { // walk of tree has same comparison - // Replace AstCCall's that point here - replaceFuncWFunc(VN_CAST(node2p, CFunc), cfunc1p); - // Replacement may promote a slow routine to fast path - if (!VN_CAST(node2p, CFunc)->slow()) cfunc1p->slow(false); - } + for (const bool slow : {false, true}) { + for (auto newIt = m_dupFinder.begin(); newIt != m_dupFinder.end(); ++newIt) { + AstCFunc* const newfuncp = VN_CAST(newIt->second, CFunc); + UASSERT_OBJ(newfuncp, newIt->second, "Not a CFunc in hash"); + if (newfuncp->user3()) continue; // Already replaced + if (newfuncp->slow() != slow) continue; + auto oldIt = newIt; + ++oldIt; // Skip over current position + for (; oldIt != m_dupFinder.end(); ++oldIt) { + AstCFunc* const oldfuncp = VN_CAST(oldIt->second, CFunc); + UASSERT_OBJ(oldfuncp, oldIt->second, "Not a CFunc in hash"); + UASSERT_OBJ(newfuncp != oldfuncp, newfuncp, + "Same function hashed multiple times"); + if (newIt->first != oldIt->first) break; // Iterate over same hashes only + if (oldfuncp->user3()) continue; // Already replaced + if (!newfuncp->sameTree(oldfuncp)) continue; // Different functions + + // Replace calls to oldfuncp with calls to newfuncp + UINFO(5, " Replace CFunc " << newIt->first << " " << newfuncp << endl); + UINFO(5, " with " << oldIt->first << " " << oldfuncp << endl); + ++m_cfuncsCombined; + oldfuncp->user3SetOnce(); // Mark replaced + m_call.replaceFunc(oldfuncp, newfuncp); + oldfuncp->unlinkFrBack(); + // Replacement may promote a slow routine to fast path + if (!oldfuncp->slow()) newfuncp->slow(false); + VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); } } } } - void replaceFuncWFunc(AstCFunc* oldfuncp, AstCFunc* newfuncp) { - UINFO(5, " DupFunc " << std::hex << V3Hash(newfuncp->user4p()) << " " << newfuncp - << endl); - UINFO(5, " and " << std::hex << V3Hash(oldfuncp->user4p()) << " " << oldfuncp - << endl); - // Mark user3p on entire old tree, so we don't process it more - ++m_statCombs; - CombMarkVisitor visitor(oldfuncp); - m_call.replaceFunc(oldfuncp, newfuncp); - oldfuncp->unlinkFrBack(); - VL_DO_DANGLING(pushDeletep(oldfuncp), oldfuncp); - } - -#ifdef VL_COMBINE_STATEMENTS - void replaceOnlyCallFunc(AstCCall* nodep) { - if (AstCFunc* oldfuncp = VN_CAST(nodep->backp(), CFunc)) { - // oldfuncp->dumpTree(cout, "MAYDEL: "); - if (nodep->nextp() == nullptr && oldfuncp->initsp() == nullptr - && oldfuncp->stmtsp() == nodep && oldfuncp->finalsp() == nullptr) { - UINFO(9, " Function only has call " << oldfuncp << endl); - m_call.deleteCall(nodep); - CombMarkVisitor visitor(oldfuncp); - VL_DO_DANGLING(replaceFuncWFunc(oldfuncp, nodep->funcp()), nodep); - } - } - } - - void walkDupCodeStart(AstNode* node1p) { - V3Hash hashval(node1p->user4p()); - // UINFO(4," STMT " << hashval << " " << node1p << endl); - // - int bestDepth = 0; // Best substitution found in the search - AstNode* bestNode2p = nullptr; - AstNode* bestLast1p = nullptr; - AstNode* bestLast2p = nullptr; - // - std::pair eqrange - = m_hashed.mmap().equal_range(hashval); - for (V3Hashed::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) { - AstNode* node2p = eqit->second; - if (node1p == node2p) continue; - // - // We need to mark iteration to prevent matching code inside - // code (abab matching in ababab) - AstNode::user1ClearTree(); // user1p() used on entire tree - m_walkLast1p = nullptr; - m_walkLast2p = nullptr; - int depth = walkDupCodeNext(node1p, node2p, 1); - if (depth > COMBINE_MIN_STATEMENTS && depth > bestDepth) { - bestDepth = depth; - bestNode2p = node2p; - bestLast1p = m_walkLast1p; - bestLast2p = m_walkLast2p; - } - } - if (bestDepth) { - // Found a replacement - UINFO(5, " Duplicate of depth " << bestDepth << endl); - UINFO(5, " DupFunc " - << " " << node1p << endl); - UINFO(5, " and " - << " " << bestNode2p << endl); - UINFO(5, " Through " - << " " << bestLast1p << endl); - UINFO(5, " and " - << " " << bestLast2p << endl); - // - walkReplace(node1p, bestNode2p, bestLast1p, bestLast2p); - } - } - - int walkDupCodeNext(AstNode* node1p, AstNode* node2p, int level) { - // Find number of common statements between the two node1p_nextp's... - if (node1p->user1p() || node2p->user1p()) return 0; // Already iterated - if (node1p->user3p() || node2p->user3p()) return 0; // Already merged - if (!m_hashed.sameNodes(node1p, node2p)) return 0; // walk of tree has same comparison - V3Hash hashval(node1p->user4p()); - // UINFO(9, " wdup1 "<user4p())<<" "<user4p())<<" "<user1(true); - node2p->user1(true); - if (node1p->nextp() && node2p->nextp()) { - return hashval.depth() + walkDupCodeNext(node1p->nextp(), node2p->nextp(), level + 1); - } - return hashval.depth(); - } - - void walkReplace(AstNode* node1p, AstNode* node2p, AstNode* last1p, - AstNode* last2p) { // Final node in linked list, maybe null if all statements - // to be grabbed - // Make new function - string oldname = m_cfuncp->name(); - string::size_type pos; - if ((pos = oldname.find("_common")) != string::npos) oldname.erase(pos); - if ((pos = oldname.find("__")) != string::npos) oldname.erase(pos); - AstCFunc* newfuncp = new AstCFunc(node1p->fileline(), - oldname + "_common" + cvtToStr(++m_modNFuncs), nullptr); - m_modp->addStmtp(newfuncp); - // Create calls - AstCCall* call1p = new AstCCall(node1p->fileline(), newfuncp); - AstCCall* call2p = new AstCCall(node2p->fileline(), newfuncp); - // Grab statement bodies - AstNRelinker relink1Handle; - AstNRelinker relink2Handle; - for (AstNode *nextp, *walkp = node1p; true; walkp = nextp) { - nextp = walkp->nextp(); - if (walkp == node1p) { - walkp->unlinkFrBack(&relink1Handle); - } else { - walkp->unlinkFrBack(); - node1p->addNext(walkp); - } - if (walkp == last1p) break; - } - for (AstNode *nextp, *walkp = node2p; true; walkp = nextp) { - nextp = walkp->nextp(); - if (walkp == node2p) { - walkp->unlinkFrBack(&relink2Handle); - } else { - walkp->unlinkFrBack(); - node2p->addNext(walkp); - } - if (walkp == last2p) break; - } - // Move node1 statements to new function - newfuncp->addStmtsp(node1p); - // newfuncp->dumpTree(cout, " newfunctree: "); - // Mark node2 statements as dead - CombMarkVisitor visitor(node2p); - pushDeletep(node2p); // Delete later - // Link in new function - relink1Handle.relink(call1p); - relink2Handle.relink(call2p); - // Hash the new function - hashFunctions(newfuncp); - m_call.addCall(call1p); - m_call.addCall(call2p); - // If either new statement makes a func with only a single call, replace - // the above callers to call it directly - VL_DO_DANGLING(replaceOnlyCallFunc(call1p), call1p); - VL_DO_DANGLING(replaceOnlyCallFunc(call2p), call2p); - } -#endif // VISITORS virtual void visit(AstNetlist* nodep) override { - // Track all callers of each function - m_call.main(nodep); - // - // In V3Hashed AstNode::user4ClearTree(); // user4p() used on entire tree - // Iterate modules backwards, in bottom-up order. - // Required so that a module instantiating another can benefit from collapsing. - iterateChildrenBackwards(nodep); + m_call.main(nodep); // Track all call sites of each function + iterateChildren(nodep); } virtual void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); - m_modp = nodep; - m_modNFuncs = 0; - m_walkLast2p = nullptr; - m_hashed.clear(); - // Compute hash of all statement trees in the function - m_state = STATE_HASH; + m_dupFinder.clear(); + // Compute hash of all CFuncs in the module iterateChildren(nodep); - m_state = STATE_IDLE; - if (debug() >= 9) m_hashed.dumpFilePrefixed("combine"); + if (debug() >= 9) m_dupFinder.dumpFilePrefixed("combine"); // Walk the hashes removing empty functions walkEmptyFuncs(); // Walk the hashes looking for duplicate functions walkDupFuncs(); - // Walk the statements looking for large replicated code sections - // Note this is disabled, it still needed work - // Also repair it for DPI functions; when make __common need to ensure proper - // flags get inherited from the old to new AstCFunc, and that AstText doesn't - // get split between functions causing the text to have a dangling reference. -#ifdef VL_COMBINE_STATEMENTS - { - m_state = STATE_DUP; - iterateChildren(nodep); - m_state = STATE_IDLE; - } -#endif - m_modp = nullptr; } virtual void visit(AstCFunc* nodep) override { - VL_RESTORER(m_cfuncp); - m_cfuncp = nodep; - if (!nodep->dontCombine()) { - if (m_state == STATE_HASH) { - hashStatement(nodep); // Hash the entire function - it might be identical - } -#ifdef VL_COMBINE_STATEMENTS - else if (m_state == STATE_DUP) { - iterateChildren(nodep); - } -#endif - } - } - virtual void visit(AstNodeStmt* nodep) override { - if (!nodep->isStatement()) { - iterateChildren(nodep); - return; - } - if (m_state == STATE_HASH && m_cfuncp) { - hashStatement(nodep); - } -#ifdef VL_COMBINE_STATEMENTS - else if (m_state == STATE_DUP && m_cfuncp) { - walkDupCodeStart(nodep); - } -#endif + if (nodep->dontCombine()) return; + // Hash the entire function + m_dupFinder.insert(nodep); } //-------------------- // Default: Just iterate - virtual void visit(AstVar*) override {} - virtual void visit(AstTraceDecl*) override {} - virtual void visit(AstTraceInc*) override {} + virtual void visit(AstVar*) override {} // Accelerate + virtual void visit(AstNodeStmt* nodep) override {} // Accelerate virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } public: // CONSTRUCTORS explicit CombineVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~CombineVisitor() override { // - V3Stats::addStat("Optimizations, Combined CFuncs", m_statCombs); + virtual ~CombineVisitor() override { + V3Stats::addStat("Optimizations, Combined CFuncs", m_cfuncsCombined); } }; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 3d87a2057..7c78cb314 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -96,18 +96,37 @@ class ConstBitOpTreeVisitor final : public AstNVisitor { ConstBitOpTreeVisitor* m_parentp; // ConstBitOpTreeVisitor that holds this VarInfo AstVarRef* m_refp; // Points the variable that this VarInfo covers V3Number m_bitPolarity; // Coefficient of each bit - static int widthOfRef(AstVarRef* refp) { - if (AstWordSel* selp = VN_CAST(refp->backp(), WordSel)) return selp->width(); - if (AstCCast* castp = VN_CAST(refp->backp(), CCast)) return castp->width(); - return refp->width(); - } public: // METHODS bool hasConstantResult() const { return m_constResult >= 0; } - bool sameVarAs(const AstNodeVarRef* otherp) const { return m_refp->sameGateTree(otherp); } + bool sameVarAs(const AstNodeVarRef* otherp) const { return m_refp->same(otherp); } void setPolarity(bool compBit, int bit) { UASSERT_OBJ(!hasConstantResult(), m_refp, "Already has result of " << m_constResult); + UASSERT_OBJ(bit < VL_QUADSIZE, m_refp, + "bit:" << bit << " is too big after V3Expand" + << " back:" << m_refp->backp()); + if (bit >= m_bitPolarity.width()) { // Need to expand m_bitPolarity + const V3Number oldPol = std::move(m_bitPolarity); + // oldPol.width() is 8, 16, or 32 because this visitor is called after V3Expand + // newWidth is increased by 2x because + // - CCast will cast to such bitwidth anyway + // - can avoid frequent expansion + int newWidth = oldPol.width(); + while (bit >= newWidth) newWidth *= 2; + m_bitPolarity = V3Number{m_refp, newWidth}; + UASSERT_OBJ(newWidth == 16 || newWidth == 32 || newWidth == 64, m_refp, + "bit:" << bit << " newWidth:" << newWidth); + m_bitPolarity.setAllBitsX(); + for (int i = 0; i < oldPol.width(); ++i) { + if (oldPol.bitIs0(i)) + m_bitPolarity.setBit(i, '0'); + else if (oldPol.bitIs1(i)) + m_bitPolarity.setBit(i, '1'); + } + } + UASSERT_OBJ(bit < m_bitPolarity.width(), m_refp, + "bit:" << bit << " width:" << m_bitPolarity.width() << m_refp); if (m_bitPolarity.bitIsX(bit)) { // The bit is not yet set m_bitPolarity.setBit(bit, compBit); } else { // Priviously set the bit @@ -129,7 +148,7 @@ class ConstBitOpTreeVisitor final : public AstNVisitor { FileLine* fl = m_refp->fileline(); AstNode* srcp = VN_CAST(m_refp->backp(), WordSel); if (!srcp) srcp = m_refp; - const int width = widthOfRef(m_refp); + const int width = m_bitPolarity.width(); if (hasConstantResult()) return new AstConst{fl, @@ -160,7 +179,7 @@ class ConstBitOpTreeVisitor final : public AstNVisitor { VarInfo(ConstBitOpTreeVisitor* parent, AstVarRef* refp) : m_parentp(parent) , m_refp(refp) - , m_bitPolarity(refp, widthOfRef(refp)) { + , m_bitPolarity(refp, refp->isWide() ? VL_EDATASIZE : refp->width()) { m_bitPolarity.setAllBitsX(); } }; @@ -1700,7 +1719,7 @@ private: VL_DO_DANGLING(streamp->deleteTree(), streamp); // Further reduce, any of the nodes may have more reductions. return true; - } else if (replaceAssignMultiSel(nodep)) { + } else if (m_doV && replaceAssignMultiSel(nodep)) { return true; } return false; diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index 48cf67fad..f0f30c098 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -22,7 +22,7 @@ #include "V3Global.h" #include "V3CoverageJoin.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include "V3Stats.h" #include @@ -33,10 +33,7 @@ class CoverageJoinVisitor final : public AstNVisitor { private: // NODE STATE - // V3Hashed - // AstCoverToggle->VarRef::user4() // V3Hashed calculation - - // AstUser4InUse In V3Hashed + // AstUser4InUse In V3Hasher via V3DupFinder // STATE std::vector m_toggleps; // List of of all AstCoverToggle's @@ -49,9 +46,9 @@ private: void detectDuplicates() { UINFO(9, "Finding duplicates\n"); // Note uses user4 - V3Hashed hashed; // Duplicate code detection + V3DupFinder dupFinder; // Duplicate code detection // Hash all of the original signals we toggle cover - for (AstCoverToggle* nodep : m_toggleps) hashed.hashAndInsert(nodep->origp()); + for (AstCoverToggle* nodep : m_toggleps) dupFinder.insert(nodep->origp()); // Find if there are any duplicates for (AstCoverToggle* nodep : m_toggleps) { // nodep->backp() is null if we already detected it's a duplicate and unlinked it. @@ -60,10 +57,10 @@ private: // This prevents making chains where a->b, then c->d, then b->c, as we'll // find a->b, a->c, a->d directly. while (true) { - const auto dupit = hashed.findDuplicate(nodep->origp()); - if (dupit == hashed.end()) break; + const auto dupit = dupFinder.findDuplicate(nodep->origp()); + if (dupit == dupFinder.end()) break; // - AstNode* duporigp = hashed.iteratorNodep(dupit); + AstNode* duporigp = dupit->second; // Note hashed will point to the original variable (what's // duplicated), not the covertoggle, but we need to get back to the // covertoggle which is immediately above, so: @@ -82,7 +79,7 @@ private: removep->unlinkFrBack(); VL_DO_DANGLING(pushDeletep(removep), removep); // Remove node from comparison so don't hit it again - hashed.erase(dupit); + dupFinder.erase(dupit); ++m_statToggleJoins; } } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index eaf5fb60d..66d1ff33e 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -351,7 +351,7 @@ private: new AstVarRef(nodep->fileline(), setvscp, VAccess::READ), nullptr, nullptr); UINFO(9, " Created " << postLogicp << endl); - finalp->addBodysp(postLogicp); + finalp->addStmtp(postLogicp); finalp->user3p(setvscp); // Remember IF's vset variable finalp->user4p(postLogicp); // and the associated IF, as we may be able to reuse it } diff --git a/src/V3DupFinder.cpp b/src/V3DupFinder.cpp new file mode 100644 index 000000000..061e659db --- /dev/null +++ b/src/V3DupFinder.cpp @@ -0,0 +1,92 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hashed common code into functions +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 "verilatedos.h" + +#include "V3Global.h" +#include "V3DupFinder.h" +#include "V3Ast.h" +#include "V3File.h" + +#include +#include +#include +#include + +//###################################################################### +// V3DupFinder class functions + +V3DupFinder::iterator V3DupFinder::findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp) { + const auto& er = equal_range(m_hasher(nodep)); + for (iterator it = er.first; it != er.second; ++it) { + AstNode* const node2p = it->second; + if (nodep == node2p) continue; // Same node is not a duplicate + if (checkp && !checkp->isSame(nodep, node2p)) continue; // User says it is not a duplicate + if (!nodep->sameTree(node2p)) continue; // Not the same trees + // Found duplicate! + return it; + } + return end(); +} + +void V3DupFinder::dumpFile(const string& filename, bool tree) { + const std::unique_ptr logp(V3File::new_ofstream(filename)); + if (logp->fail()) v3fatal("Can't write " << filename); + + std::unordered_map dist; + + V3Hash lasthash; + int num_in_bucket = 0; + for (auto it = cbegin(); true; ++it) { + if (it == cend() || lasthash != it->first) { + if (it != cend()) lasthash = it->first; + if (num_in_bucket) { + if (dist.find(num_in_bucket) == dist.end()) { + dist.emplace(num_in_bucket, 1); + } else { + ++dist[num_in_bucket]; + } + } + num_in_bucket = 0; + } + if (it == cend()) break; + num_in_bucket++; + } + *logp << "\n*** STATS:\n\n"; + *logp << " #InBucket Occurrences\n"; + for (const auto& i : dist) { + *logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << '\n'; + } + + *logp << "\n*** Dump:\n\n"; + for (const auto& it : *this) { + if (lasthash != it.first) { + lasthash = it.first; + *logp << " " << it.first << '\n'; + } + *logp << "\t" << it.second << '\n'; + // Dumping the entire tree may make nearly N^2 sized dumps, + // because the nodes under this one may also be in the hash table! + if (tree) it.second->dumpTree(*logp, " "); + } +} + +void V3DupFinder::dumpFilePrefixed(const string& nameComment, bool tree) { + if (v3Global.opt.dumpTree()) { // + dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); + } +} diff --git a/src/V3DupFinder.h b/src/V3DupFinder.h new file mode 100644 index 000000000..0b512462e --- /dev/null +++ b/src/V3DupFinder.h @@ -0,0 +1,78 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hash AST trees to find duplicates +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2005-2021 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 +// +//************************************************************************* +// +// Datastructure for finding duplicate AstNode trees via hashing +// +//************************************************************************* + +#ifndef VERILATOR_V3DUPFINDER_H_ +#define VERILATOR_V3DUPFINDER_H_ +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Error.h" +#include "V3Ast.h" +#include "V3Hasher.h" + +#include + +//============================================================================ + +struct V3DupFinderUserSame { + // Functor for V3DupFinder::findDuplicate + virtual bool isSame(AstNode*, AstNode*) = 0; + V3DupFinderUserSame() = default; + virtual ~V3DupFinderUserSame() = default; +}; + +// This really is just a multimap from 'node hash' to 'node pointer', with some minor extensions. +class V3DupFinder final : private std::multimap { + using Super = std::multimap; + + // MEMBERS + const V3Hasher m_hasher; + +public: + // CONSTRUCTORS + V3DupFinder(){}; + ~V3DupFinder() = default; + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + // Expose minimal set of superclass interface + using Super::begin; + using Super::cbegin; + using Super::cend; + using Super::clear; + using Super::const_iterator; + using Super::empty; + using Super::end; + using Super::erase; + using Super::iterator; + + // Insert node into data structure + iterator insert(AstNode* nodep) { return emplace(m_hasher(nodep), nodep); } + + // Return duplicate, if one was inserted, with optional user check for sameness + iterator findDuplicate(AstNode* nodep, V3DupFinderUserSame* checkp = nullptr); + + // Dump for debug + void dumpFile(const string& filename, bool tree); + void dumpFilePrefixed(const string& nameComment, bool tree = false); +}; + +#endif // Guard diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index eae2581cd..d71fdd96b 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -459,7 +459,7 @@ public: iterateChildren(nodep); } virtual void visit(AstCoverDecl* nodep) override { - puts("__vlCoverInsert("); // As Declared in emitCoverageDecl + puts("self->__vlCoverInsert("); // As Declared in emitCoverageDecl puts("&(vlSymsp->__Vcoverage["); puts(cvtToStr(nodep->dataDeclThisp()->binNum())); puts("])"); @@ -812,11 +812,19 @@ public: if (!nodep->branchPred().unknown()) puts(")"); puts(") {\n"); iterateAndNextNull(nodep->ifsp()); - if (nodep->elsesp()) { - puts("} else {\n"); - iterateAndNextNull(nodep->elsesp()); + puts("}"); + if (!nodep->elsesp()) { + puts("\n"); + } else { + if (VN_IS(nodep->elsesp(), NodeIf) && !nodep->elsesp()->nextp()) { + puts(" else "); + iterateAndNextNull(nodep->elsesp()); + } else { + puts(" else {\n"); + iterateAndNextNull(nodep->elsesp()); + puts("}\n"); + } } - puts("}\n"); } virtual void visit(AstExprStmt* nodep) override { // GCC allows compound statements in expressions, but this is not standard. @@ -1335,6 +1343,7 @@ unsigned EmitVarTspSorter::s_serialNext = 0; class EmitCImp final : EmitCStmts { // MEMBERS AstNodeModule* m_modp = nullptr; + AstNodeModule* m_fileModp = nullptr; // Files (names, headers) constructed using this module std::vector m_blkChangeDetVec; // All encountered changes in block bool m_slow = false; // Creating __Slow file bool m_fast = false; // Creating non __Slow file (or both) @@ -1383,8 +1392,8 @@ class EmitCImp final : EmitCStmts { } } - V3OutCFile* newOutCFile(AstNodeModule* modp, bool slow, bool source, int filenum = 0) { - string filenameNoExt = v3Global.opt.makeDir() + "/" + prefixNameProtect(modp); + V3OutCFile* newOutCFile(bool slow, bool source, int filenum = 0) { + string filenameNoExt = v3Global.opt.makeDir() + "/" + prefixNameProtect(m_fileModp); if (filenum) filenameNoExt += "__" + cvtToStr(filenum); filenameNoExt += (slow ? "__Slow" : ""); V3OutCFile* ofp = nullptr; @@ -1405,7 +1414,7 @@ class EmitCImp final : EmitCStmts { } ofp->putsHeader(); - if (modp->isTop() && !source) { + if (m_fileModp->isTop() && !source) { ofp->puts("// DESCR" "IPTION: Verilator output: Primary design header\n"); ofp->puts("//\n"); @@ -1493,7 +1502,10 @@ class EmitCImp final : EmitCStmts { } virtual void visit(AstMTaskBody* nodep) override { - ExecMTask* mtp = nodep->execMTaskp(); + maybeSplit(); + splitSizeInc(10); + + const ExecMTask* const mtp = nodep->execMTaskp(); puts("\n"); puts("void "); puts(prefixNameProtect(m_modp) + "::" + protect(mtp->cFuncName())); @@ -1517,6 +1529,8 @@ class EmitCImp final : EmitCStmts { if (nodep->dpiImport()) return; if (!(nodep->slow() ? m_slow : m_fast)) return; + maybeSplit(); + m_blkChangeDetVec.clear(); splitSizeInc(nodep); @@ -1739,7 +1753,9 @@ class EmitCImp final : EmitCStmts { } void emitVarReset(AstVar* varp) { - AstNodeDType* dtypep = varp->dtypep()->skipRefp(); + AstNodeDType* const dtypep = varp->dtypep()->skipRefp(); + const string varNameProtected + = VN_IS(m_modp, Class) ? varp->nameProtect() : "self->" + varp->nameProtect(); if (varp->isIO() && m_modp->isTop() && optSystemC()) { // System C top I/O doesn't need loading, as the lower level subinst code does it.} } else if (varp->isParam()) { @@ -1752,53 +1768,53 @@ class EmitCImp final : EmitCStmts { if (initarp->defaultp()) { puts("for (int __Vi=0; __Vi<" + cvtToStr(adtypep->elementsConst())); puts("; ++__Vi) {\n"); - emitSetVarConstant(varp->nameProtect() + "[__Vi]", + emitSetVarConstant(varNameProtected + "[__Vi]", VN_CAST(initarp->defaultp(), Const)); puts("}\n"); } const AstInitArray::KeyItemMap& mapr = initarp->map(); for (const auto& itr : mapr) { AstNode* valuep = itr.second->valuep(); - emitSetVarConstant(varp->nameProtect() + "[" + cvtToStr(itr.first) + "]", + emitSetVarConstant(varNameProtected + "[" + cvtToStr(itr.first) + "]", VN_CAST(valuep, Const)); } } else { varp->v3fatalSrc("InitArray under non-arrayed var"); } } else { - puts(emitVarResetRecurse(varp, dtypep, 0, "")); + puts(emitVarResetRecurse(varp, varNameProtected, dtypep, 0, "")); } } - string emitVarResetRecurse(AstVar* varp, AstNodeDType* dtypep, int depth, - const string& suffix) { + string emitVarResetRecurse(const AstVar* varp, const string& varNameProtected, + AstNodeDType* dtypep, int depth, const string& suffix) { dtypep = dtypep->skipRefp(); AstBasicDType* basicp = dtypep->basicp(); // Returns string to do resetting, empty to do nothing (which caller should handle) if (AstAssocArrayDType* adtypep = VN_CAST(dtypep, AssocArrayDType)) { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, - ".atDefault()" + cvtarray); + return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1, + suffix + ".atDefault()" + cvtarray); } else if (VN_IS(dtypep, ClassRefDType)) { return ""; // Constructor does it } else if (AstDynArrayDType* adtypep = VN_CAST(dtypep, DynArrayDType)) { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, - ".atDefault()" + cvtarray); + return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1, + suffix + ".atDefault()" + cvtarray); } else if (AstQueueDType* adtypep = VN_CAST(dtypep, QueueDType)) { // Access std::array as C array string cvtarray = (adtypep->subDTypep()->isWide() ? ".data()" : ""); - return emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, - ".atDefault()" + cvtarray); + return emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), depth + 1, + suffix + ".atDefault()" + cvtarray); } else if (AstUnpackArrayDType* adtypep = VN_CAST(dtypep, UnpackArrayDType)) { UASSERT_OBJ(adtypep->hi() >= adtypep->lo(), varp, "Should have swapped msb & lsb earlier."); string ivar = string("__Vi") + cvtToStr(depth); string pre = ("for (int " + ivar + "=" + cvtToStr(0) + "; " + ivar + "<" + cvtToStr(adtypep->elementsConst()) + "; ++" + ivar + ") {\n"); - string below = emitVarResetRecurse(varp, adtypep->subDTypep(), depth + 1, - suffix + "[" + ivar + "]"); + string below = emitVarResetRecurse(varp, varNameProtected, adtypep->subDTypep(), + depth + 1, suffix + "[" + ivar + "]"); string post = "}\n"; return below.empty() ? "" : pre + below + post; } else if (basicp && basicp->keyword() == AstBasicDTypeKwd::STRING) { @@ -1814,16 +1830,21 @@ class EmitCImp final : EmitCStmts { splitSizeInc(1); if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide string out; - if (zeroit) { - out += "VL_ZERO_RESET_W("; + if (varp->valuep()) { + AstConst* const constp = VN_CAST(varp->valuep(), Const); + if (!constp) varp->v3fatalSrc("non-const initializer for variable"); + for (int w = 0; w < varp->widthWords(); ++w) { + out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = "; + out += cvtToStr(constp->num().edataWord(w)) + "U;\n"; + } } else { - out += "VL_RAND_RESET_W("; + out += zeroit ? "VL_ZERO_RESET_W(" : "VL_RAND_RESET_W("; + out += cvtToStr(dtypep->widthMin()); + out += ", " + varNameProtected + suffix + ");\n"; } - out += cvtToStr(dtypep->widthMin()); - out += ", " + varp->nameProtect() + suffix + ");\n"; return out; } else { - string out = varp->nameProtect() + suffix; + string out = varNameProtected + suffix; // If --x-initial-edge is set, we want to force an initial // edge on uninitialized clocks (from 'X' to whatever the // first value is). Since the class is instantiated before @@ -1855,8 +1876,8 @@ class EmitCImp final : EmitCStmts { void emitSavableImp(AstNodeModule* modp); void emitTextSection(AstType type); // High level - void emitImpTop(AstNodeModule* modp); - void emitImp(AstNodeModule* fileModp, AstNodeModule* modp); + void emitImpTop(); + void emitImp(AstNodeModule* modp); void emitSettleLoop(const std::string& eval_call, bool initial); void emitWrapEval(AstNodeModule* modp); void emitWrapFast(AstNodeModule* modp); @@ -1864,7 +1885,7 @@ class EmitCImp final : EmitCStmts { void emitMTaskVertexCtors(bool* firstp); void emitIntTop(AstNodeModule* modp); void emitInt(AstNodeModule* modp); - void maybeSplit(AstNodeModule* modp); + void maybeSplit(); public: EmitCImp() = default; @@ -2263,6 +2284,19 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const emitDispState.pushArg(' ', nullptr, cvtToStr(argp->widthMin())); } emitDispState.pushArg(fmtLetter, argp, ""); + if (fmtLetter == 't' || fmtLetter == '^') { + AstSFormatF* fmtp = nullptr; + if (AstDisplay* nodep = VN_CAST(dispp, Display)) + fmtp = nodep->fmtp(); + else if (AstSFormat* nodep = VN_CAST(dispp, SFormat)) + fmtp = nodep->fmtp(); + else + fmtp = VN_CAST(dispp, SFormatF); + UASSERT_OBJ(fmtp, dispp, + "Use of %t must be under AstDisplay, AstSFormat, or AstSFormatF"); + UASSERT_OBJ(!fmtp->timeunit().isNone(), fmtp, "timenunit must be set"); + emitDispState.pushArg(' ', nullptr, cvtToStr((int)fmtp->timeunit().powerOfTen())); + } } else { emitDispState.pushArg(fmtLetter, nullptr, ""); } @@ -2449,7 +2483,7 @@ void EmitCImp::emitCtorImp(AstNodeModule* modp) { puts("\n"); } putsDecoration("// Reset structure values\n"); - puts(protect("_ctor_var_reset") + "();\n"); + puts(protect("_ctor_var_reset") + "(this);\n"); emitTextSection(AstType::atScCtor); if (modp->isTop() && v3Global.opt.mtasks()) { @@ -2492,7 +2526,9 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) { puts("if (false && first) {} // Prevent unused\n"); puts("this->__VlSymsp = vlSymsp;\n"); // First, as later stuff needs it. puts("if (false && this->__VlSymsp) {} // Prevent unused\n"); - if (v3Global.opt.coverage()) { puts(protect("_configure_coverage") + "(vlSymsp, first);\n"); } + if (v3Global.opt.coverage()) { + puts(protect("_configure_coverage") + "(this, vlSymsp, first);\n"); + } if (modp->isTop() && !v3Global.rootp()->timeunit().isNone()) { puts("vlSymsp->_vm_contextp__->timeunit(" + cvtToStr(v3Global.rootp()->timeunit().powerOfTen()) + ");\n"); @@ -3088,10 +3124,7 @@ void EmitCImp::emitIntTop(AstNodeModule*) { } if (v3Global.opt.mtasks()) puts("#include \"verilated_threads.h\"\n"); if (v3Global.opt.savable()) puts("#include \"verilated_save.h\"\n"); - if (v3Global.opt.coverage()) { - puts("#include \"verilated_cov.h\"\n"); - if (v3Global.opt.savable()) v3error("--coverage and --savable not supported together"); - } + if (v3Global.opt.coverage()) puts("#include \"verilated_cov.h\"\n"); if (v3Global.dpi()) { // do this before including our main .h file so that any references to // types defined in svdpi.h are available @@ -3338,9 +3371,9 @@ void EmitCImp::emitInt(AstNodeModule* modp) { //---------------------------------------------------------------------- -void EmitCImp::emitImpTop(AstNodeModule* fileModp) { +void EmitCImp::emitImpTop() { puts("\n"); - puts("#include \"" + prefixNameProtect(fileModp) + ".h\"\n"); + puts("#include \"" + prefixNameProtect(m_fileModp) + ".h\"\n"); puts("#include \"" + symClassName() + ".h\"\n"); if (v3Global.dpi()) { @@ -3348,13 +3381,13 @@ void EmitCImp::emitImpTop(AstNodeModule* fileModp) { puts("#include \"verilated_dpi.h\"\n"); } - emitModCUse(fileModp, VUseType::IMP_INCLUDE); - emitModCUse(fileModp, VUseType::IMP_FWD_CLASS); + emitModCUse(m_fileModp, VUseType::IMP_INCLUDE); + emitModCUse(m_fileModp, VUseType::IMP_FWD_CLASS); emitTextSection(AstType::atScImpHdr); } -void EmitCImp::emitImp(AstNodeModule* fileModp, AstNodeModule* modp) { +void EmitCImp::emitImp(AstNodeModule* modp) { puts("\n//==========\n"); if (m_slow) { string section; @@ -3376,37 +3409,33 @@ void EmitCImp::emitImp(AstNodeModule* fileModp, AstNodeModule* modp) { // Blocks for (AstNode* nodep = modp->stmtsp(); nodep; nodep = nodep->nextp()) { - if (AstCFunc* funcp = VN_CAST(nodep, CFunc)) { - maybeSplit(fileModp); - mainDoFunc(funcp); - } + if (AstCFunc* funcp = VN_CAST(nodep, CFunc)) { mainDoFunc(funcp); } } } //###################################################################### -void EmitCImp::maybeSplit(AstNodeModule* fileModp) { - if (splitNeeded()) { - // Splitting file, so using parallel build. - v3Global.useParallelBuild(true); - // Close old file - VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); - // Open a new file - m_ofp = newOutCFile(fileModp, !m_fast, true /*source*/, splitFilenumInc()); - emitImpTop(fileModp); - } - splitSizeInc(10); // Even blank functions get a file with a low csplit +void EmitCImp::maybeSplit() { + if (!splitNeeded()) return; + + // Splitting file, so using parallel build. + v3Global.useParallelBuild(true); + // Close old file + VL_DO_CLEAR(delete m_ofp, m_ofp = nullptr); + // Open a new file + m_ofp = newOutCFile(!m_fast, true /*source*/, splitFilenumInc()); + emitImpTop(); } void EmitCImp::mainInt(AstNodeModule* modp) { - AstNodeModule* fileModp = modp; // Filename constructed using this module m_modp = modp; + m_fileModp = modp; m_slow = true; m_fast = true; UINFO(5, " Emitting " << prefixNameProtect(modp) << endl); - m_ofp = newOutCFile(fileModp, false /*slow*/, false /*source*/); + m_ofp = newOutCFile(false /*slow*/, false /*source*/); emitIntTop(modp); emitInt(modp); if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) { @@ -3421,23 +3450,23 @@ void EmitCImp::mainInt(AstNodeModule* modp) { void EmitCImp::mainImp(AstNodeModule* modp, bool slow) { // Output a module - AstNodeModule* fileModp = modp; // Filename constructed using this module m_modp = modp; + m_fileModp = modp; m_slow = slow; m_fast = !slow; UINFO(5, " Emitting " << prefixNameProtect(modp) << endl); - m_ofp = newOutCFile(fileModp, !m_fast, true /*source*/); - emitImpTop(fileModp); - emitImp(fileModp, modp); + m_ofp = newOutCFile(!m_fast, true /*source*/); + emitImpTop(); + emitImp(modp); if (AstClassPackage* packagep = VN_CAST(modp, ClassPackage)) { // Put the non-static class implementation in same C++ files as // often optimizations are possible when both are seen by the // compiler together m_modp = packagep->classp(); - emitImp(fileModp, packagep->classp()); + emitImp(packagep->classp()); m_modp = modp; } @@ -3450,7 +3479,6 @@ void EmitCImp::mainImp(AstNodeModule* modp, bool slow) { vxp = vxp->verticesNextp()) { const ExecMTask* mtaskp = dynamic_cast(vxp); if (mtaskp->threadRoot()) { - maybeSplit(fileModp); // Only define one function for all the mtasks packed on // a given thread. We'll name this function after the // root mtask though it contains multiple mtasks' worth @@ -3925,21 +3953,29 @@ void V3EmitC::emitc() { for (AstNodeModule* nodep = v3Global.rootp()->modulesp(); nodep; nodep = VN_CAST(nodep->nextp(), NodeModule)) { if (VN_IS(nodep, Class)) continue; // Imped with ClassPackage - // clang-format off - EmitCImp cint; cint.mainInt(nodep); - cint.mainImp(nodep, true); - { EmitCImp fast; fast.mainImp(nodep, false); } - // clang-format on + { + EmitCImp cint; + cint.mainInt(nodep); + cint.mainImp(nodep, true); + } + { + EmitCImp fast; + fast.mainImp(nodep, false); + } } } void V3EmitC::emitcTrace() { UINFO(2, __FUNCTION__ << ": " << endl); if (v3Global.opt.trace()) { - // clang-format off - { EmitCTrace slow(true); slow.main(); } - { EmitCTrace fast(false); fast.main(); } - // clang-format on + { + EmitCTrace slow(true); + slow.main(); + } + { + EmitCTrace fast(false); + fast.main(); + } } } diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index e9097abde..a2aa6bd78 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -113,6 +113,10 @@ class CMakeEmitter final { cmake_set_raw(*of, name + "_COVERAGE", v3Global.opt.coverage() ? "1" : "0"); *of << "# Threaded output mode? 0/1/N threads (from --threads)\n"; cmake_set_raw(*of, name + "_THREADS", cvtToStr(v3Global.opt.threads())); + *of << "# Threaded tracing output mode? 0/1/N threads (from --trace-threads)\n"; + cmake_set_raw(*of, name + "_TRACE_THREADS", cvtToStr(v3Global.opt.traceThreads())); + *of << "# Struct output mode? 0/1 (from --trace-structs)\n"; + cmake_set_raw(*of, name + "_TRACE_STRUCTS", cvtToStr(v3Global.opt.traceStructs())); *of << "# VCD Tracing output mode? 0/1 (from --trace)\n"; cmake_set_raw(*of, name + "_TRACE_VCD", (v3Global.opt.trace() && (v3Global.opt.traceFormat() == TraceFormat::VCD)) @@ -167,11 +171,6 @@ class CMakeEmitter final { global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceBase() + "_c.cpp"); if (v3Global.opt.systemC()) { - if (v3Global.opt.traceFormat() != TraceFormat::VCD) { - v3warn(E_UNSUPPORTED, - "Unsupported: This trace format is not supported in SystemC, " - "use VCD format."); - } global.emplace_back("${VERILATOR_ROOT}/include/" + v3Global.opt.traceSourceLang() + ".cpp"); } diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index bf3953e8e..a04288b68 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -170,7 +170,12 @@ class EmitCSyms final : EmitCBaseVisitor { const auto scpit = m_vpiScopeCandidates.find(scp); if ((scpit != m_vpiScopeCandidates.end()) && (m_scopeNames.find(scp) == m_scopeNames.end())) { - m_scopeNames.emplace(scpit->second.m_symName, scpit->second); + auto scopeNameit = m_scopeNames.find(scpit->second.m_symName); + if (scopeNameit == m_scopeNames.end()) { + m_scopeNames.emplace(scpit->second.m_symName, scpit->second); + } else { + scopeNameit->second.m_type = scpit->second.m_type; + } } string::size_type pos = scp.rfind("__DOT__"); if (pos == string::npos) { @@ -233,20 +238,20 @@ class EmitCSyms final : EmitCBaseVisitor { ++it) { if (it->second.m_type != "SCOPE_MODULE") continue; - string name = it->second.m_prettyName; - if (name.substr(0, 4) == "TOP.") name.replace(0, 4, ""); + string symName = it->second.m_symName; + string above = symName; + if (above.substr(0, 4) == "TOP.") above.replace(0, 4, ""); - string above = name; while (!above.empty()) { - string::size_type pos = above.rfind('.'); + string::size_type pos = above.rfind("__"); if (pos == string::npos) break; above.resize(pos); if (m_vpiScopeHierarchy.find(above) != m_vpiScopeHierarchy.end()) { - m_vpiScopeHierarchy[above].push_back(name); + m_vpiScopeHierarchy[above].push_back(symName); break; } } - m_vpiScopeHierarchy[name] = std::vector(); + m_vpiScopeHierarchy[symName] = std::vector(); } } @@ -757,6 +762,7 @@ void EmitCSyms::emitSymImp() { AstScope* scopep = it->second.m_scopep; AstVar* varp = it->second.m_varp; // + int pwidth = 1; int pdim = 0; int udim = 0; string bounds; @@ -768,6 +774,7 @@ void EmitCSyms::emitSymImp() { bounds += ","; bounds += cvtToStr(basicp->lo()); pdim++; + pwidth *= basicp->elements(); } for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) { dtypep @@ -779,6 +786,7 @@ void EmitCSyms::emitSymImp() { bounds += cvtToStr(adtypep->right()); if (VN_IS(dtypep, PackArrayDType)) { pdim++; + pwidth *= adtypep->elementsConst(); } else { udim++; } @@ -788,8 +796,14 @@ void EmitCSyms::emitSymImp() { } } } - // - if (udim > 1 && (pdim && udim)) { + // TODO: actually expose packed arrays as vpiRegArray + if (pdim > 1 && udim == 0) { + bounds = ", "; + bounds += cvtToStr(pwidth - 1); + bounds += ",0"; + pdim = 1; + } + if (pdim > 1 || udim > 1) { puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays } puts(protect("__Vscope_" + it->second.m_scopeName) + ".varInsert(__Vfinal,"); diff --git a/src/V3Error.h b/src/V3Error.h index eb1cff471..870893c8e 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -64,6 +64,7 @@ public: ALWCOMBORDER, // Always_comb with unordered statements ASSIGNDLY, // Assignment delays ASSIGNIN, // Assigning to input + BADSTDPRAGMA, // Any error related to pragmas BLKANDNBLK, // Blocked and non-blocking assignments to same variable BLKLOOPINIT, // Delayed assignment to array inside for loops BLKSEQ, // Blocking assignments in sequential block @@ -109,6 +110,7 @@ public: PINNOTFOUND, // instance port name not found in it's module PKGNODECL, // Error: Package/class needs to be predeclared PROCASSWIRE, // Procedural assignment on wire + PROTECTED, // detected `pragma protected RANDC, // Unsupported: 'randc' converted to 'rand' REALCVT, // Real conversion REDEFMACRO, // Redefining existing define macro @@ -159,7 +161,7 @@ public: "DETECTARRAY", "ENCAPSULATED", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", // Warnings " EC_FIRST_WARN", - "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", + "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA", "BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE", "CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA", "CMPCONST", "COLONPLUS", "COMBDLY", "CONTASSREG", @@ -171,7 +173,7 @@ public: "LATCH", "LITENDIAN", "MODDUP", "MULTIDRIVEN", "MULTITOP","NOLATCH", "NULLPORT", "PINCONNECTEMPTY", "PINMISSING", "PINNOCONNECT", "PINNOTFOUND", "PKGNODECL", "PROCASSWIRE", - "RANDC", "REALCVT", "REDEFMACRO", + "PROTECTED", "RANDC", "REALCVT", "REDEFMACRO", "SELRANGE", "SHORTREAL", "SPLITVAR", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET", "TICKCOUNT", "TIMESCALEMOD", "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", @@ -192,8 +194,8 @@ public: // Warnings we'll present to the user as errors // Later -Werror- options may make more of these. bool pretendError() const { - return (m_e == ASSIGNIN || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG - || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL + return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BLKANDNBLK || m_e == BLKLOOPINIT + || m_e == CONTASSREG || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL || m_e == PROCASSWIRE); // Says IEEE } // Warnings to mention manual diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index 2ec552cfe..dd5a5ec42 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -30,6 +30,7 @@ #include "V3Global.h" #include "V3Expand.h" +#include "V3Stats.h" #include "V3Ast.h" #include @@ -45,10 +46,24 @@ private: // STATE AstNode* m_stmtp = nullptr; // Current statement + VDouble0 m_statWides; // Statistic tracking + VDouble0 m_statWideWords; // Statistic tracking + VDouble0 m_statWideLimited; // Statistic tracking // METHODS VL_DEBUG_FUNC; // Declare debug() + bool doExpand(AstNode* nodep) { + ++m_statWides; + if (nodep->widthWords() <= v3Global.opt.expandLimit()) { + m_statWideWords += nodep->widthWords(); + return true; + } else { + ++m_statWideLimited; + return false; + } + } + int longOrQuadWidth(AstNode* nodep) { return (nodep->width() + (VL_EDATASIZE - 1)) & ~(VL_EDATASIZE - 1); } @@ -204,6 +219,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstConst* rhsp) { UINFO(8, " Wordize ASSIGN(CONST) " << nodep << endl); + if (!doExpand(nodep)) return false; // -> {for each_word{ ASSIGN(WORDSEL(wide,#),WORDSEL(CONST,#))}} if (rhsp->num().isFourState()) { rhsp->v3warn(E_UNSUPPORTED, // LCOV_EXCL_LINE // impossible? @@ -219,6 +235,7 @@ private: //-------- Uniops bool expandWide(AstNodeAssign* nodep, AstVarRef* rhsp) { UINFO(8, " Wordize ASSIGN(VARREF) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, newAstWordSelClone(rhsp, w)); } @@ -228,6 +245,7 @@ private: UINFO(8, " Wordize ASSIGN(ARRAYSEL) " << nodep << endl); UASSERT_OBJ(!VN_IS(nodep->dtypep()->skipRefp(), UnpackArrayDType), nodep, "ArraySel with unpacked arrays should have been removed in V3Slice"); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, newAstWordSelClone(rhsp, w)); } @@ -236,6 +254,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstNot* rhsp) { UINFO(8, " Wordize ASSIGN(NOT) " << nodep << endl); // -> {for each_word{ ASSIGN(WORDSEL(wide,#),NOT(WORDSEL(lhs,#))) }} + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstNot(rhsp->fileline(), newAstWordSelClone(rhsp->lhsp(), w))); @@ -245,6 +264,7 @@ private: //-------- Biops bool expandWide(AstNodeAssign* nodep, AstAnd* rhsp) { UINFO(8, " Wordize ASSIGN(AND) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstAnd(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), @@ -254,6 +274,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstOr* rhsp) { UINFO(8, " Wordize ASSIGN(OR) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstOr(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), @@ -263,6 +284,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstXor* rhsp) { UINFO(8, " Wordize ASSIGN(XOR) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstXor(nodep->fileline(), newAstWordSelClone(rhsp->lhsp(), w), @@ -273,6 +295,7 @@ private: //-------- Triops bool expandWide(AstNodeAssign* nodep, AstNodeCond* rhsp) { UINFO(8, " Wordize ASSIGN(COND) " << nodep << endl); + if (!doExpand(nodep)) return false; for (int w = 0; w < nodep->widthWords(); w++) { addWordAssign(nodep, w, new AstCond(nodep->fileline(), rhsp->condp()->cloneTree(true), @@ -417,6 +440,7 @@ private: bool expandWide(AstNodeAssign* nodep, AstSel* rhsp) { UASSERT_OBJ(nodep->widthMin() == rhsp->widthConst(), nodep, "Width mismatch"); + if (!doExpand(nodep)) return false; if (VN_IS(rhsp->lsbp(), Const) && VL_BITBIT_E(rhsp->lsbConst()) == 0) { int lsb = rhsp->lsbConst(); UINFO(8, " Wordize ASSIGN(SEL,align) " << nodep << endl); @@ -647,6 +671,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstConcat* rhsp) { UINFO(8, " Wordize ASSIGN(CONCAT) " << nodep << endl); + if (!doExpand(rhsp)) return false; // Lhs or Rhs may be word, long, or quad. // newAstWordSelClone nicely abstracts the difference. int rhsshift = rhsp->rhsp()->widthMin(); @@ -701,6 +726,7 @@ private: } bool expandWide(AstNodeAssign* nodep, AstReplicate* rhsp) { UINFO(8, " Wordize ASSIGN(REPLICATE) " << nodep << endl); + if (!doExpand(rhsp)) return false; AstNode* lhsp = rhsp->lhsp(); int lhswidth = lhsp->widthMin(); const AstConst* constp = VN_CAST(rhsp->rhsp(), Const); @@ -857,6 +883,7 @@ private: iterateChildren(nodep); bool did = false; if (nodep->isWide() && ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel))) + && ((VN_IS(nodep->lhsp(), VarRef) || VN_IS(nodep->lhsp(), ArraySel))) && !AstVar::scVarRecurse(nodep->lhsp()) // Need special function for SC && !AstVar::scVarRecurse(nodep->rhsp())) { if (AstConst* rhsp = VN_CAST(nodep->rhsp(), Const)) { @@ -897,7 +924,11 @@ private: public: // CONSTRUCTORS explicit ExpandVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ExpandVisitor() override = default; + virtual ~ExpandVisitor() override { + V3Stats::addStat("Optimizations, expand wides", m_statWides); + V3Stats::addStat("Optimizations, expand wide words", m_statWideWords); + V3Stats::addStat("Optimizations, expand limited", m_statWideLimited); + } }; //---------------------------------------------------------------------- diff --git a/src/V3File.cpp b/src/V3File.cpp index 63920e061..43c07ac17 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -692,7 +692,7 @@ int V3OutFormatter::endLevels(const char* strg) { } void V3OutFormatter::puts(const char* strg) { - if (m_prependIndent) { + if (m_prependIndent && strg[0] != '\n') { putsNoTracking(indentSpaces(endLevels(strg))); m_prependIndent = false; } @@ -715,9 +715,13 @@ void V3OutFormatter::puts(const char* strg) { break; case ' ': wordstart = true; break; case '\t': wordstart = true; break; + case '"': + wordstart = false; + m_inStringLiteral = !m_inStringLiteral; + break; case '/': if (m_lang == LA_C || m_lang == LA_VERILOG) { - if (cp > strg && cp[-1] == '/') { + if (cp > strg && cp[-1] == '/' && !m_inStringLiteral) { // Output ignoring contents to EOL cp++; while (*cp && cp[1] && cp[1] != '\n') putcNoTracking(*cp++); @@ -1012,7 +1016,8 @@ public: } } string protectWordsIf(const string& old, bool doIt) { - // Split at " " (for traces), "." (for scopes), or "->" (for scopes) + // Split at " " (for traces), "." (for scopes), "->" (for scopes), "::" (for superclass + // reference) if (!(doIt && v3Global.opt.protectIds())) return old; string out; string::size_type start = 0; @@ -1024,6 +1029,7 @@ public: trySep(old, start, " ", pos /*ref*/, separator /*ref*/); trySep(old, start, ".", pos /*ref*/, separator /*ref*/); trySep(old, start, "->", pos /*ref*/, separator /*ref*/); + trySep(old, start, "::", pos /*ref*/, separator /*ref*/); if (pos == string::npos) break; out += protectIf(old.substr(start, pos - start), true) + separator; start = pos + separator.length(); diff --git a/src/V3File.h b/src/V3File.h index b198a10b4..9d22a77b0 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -121,6 +121,7 @@ private: int m_column = 0; int m_nobreak = false; // Basic operator or begin paren, don't break next bool m_prependIndent = true; + bool m_inStringLiteral = false; int m_indentLevel = 0; // Current {} indentation std::stack m_parenVec; // Stack of columns where last ( was int m_bracketLevel = 0; // Intenting = { block, indicates number of {'s seen. diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 913c6c645..f9144db8d 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -30,7 +30,7 @@ #include "V3Graph.h" #include "V3Const.h" #include "V3Stats.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include #include @@ -900,7 +900,7 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* //###################################################################### // Auxiliary hash class for GateDedupeVarVisitor -class GateDedupeHash final : public V3HashedUserSame { +class GateDedupeHash final : public V3DupFinderUserSame { private: // NODE STATE // Ast*::user2p -> parent AstNodeAssign* for this rhsp @@ -911,24 +911,36 @@ private: // AstUser1InUse m_inuser1; (Allocated for use in GateVisitor) // AstUser2InUse m_inuser2; (Allocated for use in GateVisitor) AstUser3InUse m_inuser3; - // AstUser4InUse m_inuser4; (Allocated for use in V3Hashed) + // AstUser4InUse m_inuser4; (Allocated for use in V3Hasher via V3DupFinder) AstUser5InUse m_inuser5; - V3Hashed m_hashed; // Hash, contains rhs of assigns + V3DupFinder m_dupFinder; // Duplicate finder for rhs of assigns std::unordered_set m_nodeDeleteds; // Any node in this hash was deleted VL_DEBUG_FUNC; // Declare debug() - void hash(AstNode* nodep) { - // !nullptr && the object is hashable - if (nodep && !nodep->sameHash().isIllegal()) m_hashed.hash(nodep); - } - bool sameHash(AstNode* node1p, AstNode* node2p) { - return (node1p && node2p && !node1p->sameHash().isIllegal() - && !node2p->sameHash().isIllegal() && m_hashed.sameNodes(node1p, node2p)); - } bool same(AstNode* node1p, AstNode* node2p) { - return node1p == node2p || sameHash(node1p, node2p); + // Regarding the complexity of this funcition 'same': + // Applying this comparison function to a a set of n trees pairwise is O(n^2) in the + // number of comparisons (number of pairs). AstNode::sameTree itself, is O(sizeOfTree) in + // the worst case, which happens if the operands of sameTree are indeed identical copies, + // which means this line is O(n^2*sizeOfTree), iff you are comparing identical copies of + // the same tree. In practice the identity comparison over the pointers, and the short + // circuiting in sameTree means that for comparing the same tree instance to itself, or + // trees of different types/shapes is a lot closer to O(1), so this 'same' function is + // Omega(n^2) and O(n^2*sizeOfTree), and in practice as we are mostly comparing the same + // instance to itself or different trees, the complexity should be closer to the lower + // bound. + // + // Also if you see where this 'same' function is used within isSame, it's only ever + // comparing AstActive nodes, which are very likely not to compare equals (and for the + // purposes of V3Gate, we probably only care about them either being identical instances, + // or having the same sensitivities anyway, so if this becomes a problem, it can be + // improved which should also speed things up), and AstNodeMath for if conditions, which + // are hopefully small, and to be safe they should probably be only considered same when + // identical instances (otherwise if writing the condition between 2 ifs don't really + // merge). + return node1p == node2p || (node1p && node1p->sameTree(node2p)); } public: @@ -958,7 +970,7 @@ public: || (extra2p && m_nodeDeleteds.find(extra2p) != m_nodeDeleteds.end())); } - // Callback from V3Hashed::findDuplicate + // Callback from V3DupFinder::findDuplicate virtual bool isSame(AstNode* node1p, AstNode* node2p) override { // Assignment may have been hashReplaced, if so consider non-match (effectively removed) if (isReplaced(node1p) || isReplaced(node2p)) { @@ -977,25 +989,21 @@ public: rhsp->user3p(extra1p); rhsp->user5p(extra2p); - hash(extra1p); - hash(extra2p); - - const auto inserted = m_hashed.hashAndInsert(rhsp); - const auto dupit = m_hashed.findDuplicate(rhsp, this); - // Even though rhsp was just inserted, V3Hashed::findDuplicate doesn't - // return anything in the hash that has the same pointer (V3Hashed.cpp::findDuplicate) + const auto inserted = m_dupFinder.insert(rhsp); + const auto dupit = m_dupFinder.findDuplicate(rhsp, this); + // Even though rhsp was just inserted, V3DupFinder::findDuplicate doesn't + // return anything in the hash that has the same pointer (V3DupFinder::findDuplicate) // So dupit is either a different, duplicate rhsp, or the end of the hash. - if (dupit != m_hashed.end()) { - m_hashed.erase(inserted); - return VN_CAST(m_hashed.iteratorNodep(dupit)->user2p(), NodeAssign); + if (dupit != m_dupFinder.end()) { + m_dupFinder.erase(inserted); + return VN_CAST(dupit->second->user2p(), NodeAssign); } // Retain new inserted information return nullptr; } void check() { - m_hashed.check(); - for (const auto& itr : m_hashed) { + for (const auto& itr : m_dupFinder) { AstNode* nodep = itr.second; AstNode* activep = nodep->user3p(); AstNode* condVarp = nodep->user5p(); @@ -1003,9 +1011,9 @@ public: // This class won't break if activep isn't an active, or // ifVar isn't a var, but this is checking the caller's construction. UASSERT_OBJ(!activep || (!VN_DELETED(activep) && VN_IS(activep, Active)), nodep, - "V3Hashed check failed, lost active pointer"); + "V3DupFinder check failed, lost active pointer"); UASSERT_OBJ(!condVarp || !VN_DELETED(condVarp), nodep, - "V3Hashed check failed, lost if pointer"); + "V3DupFinder check failed, lost if pointer"); } } } diff --git a/src/V3Hash.cpp b/src/V3Hash.cpp new file mode 100644 index 000000000..2f1b33003 --- /dev/null +++ b/src/V3Hash.cpp @@ -0,0 +1,27 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hash calculation +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 "V3Hash.h" + +#include +#include + +V3Hash::V3Hash(const std::string& val) + : m_value{static_cast(std::hash{}(val))} {} + +std::ostream& operator<<(std::ostream& os, const V3Hash& rhs) { + return os << std::hex << std::setw(8) << std::setfill('0') << rhs.value(); +} diff --git a/src/V3Hash.h b/src/V3Hash.h new file mode 100644 index 000000000..6bb2963ba --- /dev/null +++ b/src/V3Hash.h @@ -0,0 +1,69 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hash calculation +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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_V3HASH_H_ +#define VERILATOR_V3HASH_H_ + +#include +#include + +//###################################################################### +// V3Hash -- Generic hashing + +class V3Hash final { + uint32_t m_value; // The 32-bit hash value. + +public: + // CONSTRUCTORS + V3Hash() + : m_value{0} {} + explicit V3Hash(uint32_t val) + : m_value{val + 0x9e3779b9} {} // This is the same as 'V3Hash() + val' + explicit V3Hash(int32_t val) + : m_value{static_cast(val)} {} + explicit V3Hash(size_t val) + : m_value{static_cast(val)} {} + explicit V3Hash(const std::string& val); + + // METHODS + uint32_t value() const { return m_value; } + + // OPERATORS + // Comparisons + bool operator==(const V3Hash& rh) const { return m_value == rh.m_value; } + bool operator!=(const V3Hash& rh) const { return m_value != rh.m_value; } + bool operator<(const V3Hash& rh) const { return m_value < rh.m_value; } + + // '+' combines hashes + V3Hash operator+(const V3Hash& that) const { + return V3Hash(m_value ^ (that.m_value + 0x9e3779b9 + (m_value << 6) + (m_value >> 2))); + } + V3Hash operator+(uint32_t value) const { return *this + V3Hash(value); } + V3Hash operator+(int32_t value) const { return *this + V3Hash(value); } + V3Hash operator+(size_t value) const { return *this + V3Hash(value); } + V3Hash operator+(const std::string& value) const { return *this + V3Hash(value); } + + // '+=' combines in place + V3Hash& operator+=(const V3Hash& that) { return *this = *this + that; } + V3Hash& operator+=(uint32_t value) { return *this += V3Hash(value); } + V3Hash& operator+=(int32_t value) { return *this += V3Hash(value); } + V3Hash& operator+=(size_t value) { return *this += V3Hash(value); } + V3Hash& operator+=(const std::string& that) { return *this += V3Hash(that); } +}; + +std::ostream& operator<<(std::ostream& os, const V3Hash& rhs); + +#endif // Guard diff --git a/src/V3Hashed.cpp b/src/V3Hashed.cpp deleted file mode 100644 index acfe9ba94..000000000 --- a/src/V3Hashed.cpp +++ /dev/null @@ -1,207 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Hashed common code into functions -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// Copyright 2003-2021 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 -// -//************************************************************************* -// V3Hashed's Transformations: -// -// Hash each node depth first -// Hash includes varp name and operator type, and constants -// Form lookup table based on hash of each statement w/ nodep and next nodep -// -//************************************************************************* - -#include "config_build.h" -#include "verilatedos.h" - -#include "V3Global.h" -#include "V3Hashed.h" -#include "V3Ast.h" -#include "V3File.h" - -#include -#include -#include -#include - -//###################################################################### -// Hashed state, as a visitor of each AstNode - -class HashedVisitor final : public AstNVisitor { -private: - // NODE STATE - // Entire netlist: - // AstNodeStmt::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) - // AstUser4InUse in V3Hashed.h - - // STATE - V3Hash m_lowerHash; // Hash of the statement we're building - bool m_cacheInUser4; // Use user4 to cache each V3Hash? - - // METHODS - VL_DEBUG_FUNC; // Declare debug() - - void nodeHashIterate(AstNode* nodep) { - V3Hash thisHash; - if (!m_cacheInUser4 || !nodep->user4()) { - UASSERT_OBJ( - !(VN_IS(nodep->backp(), CFunc) - && !(VN_IS(nodep, NodeStmt) || VN_IS(nodep, CFunc))), - nodep, - "Node " << nodep->prettyTypeName() - << " in statement position but not marked stmt (node under function)"); - VL_RESTORER(m_lowerHash); - { - m_lowerHash = nodep->sameHash(); - UASSERT_OBJ(!m_lowerHash.isIllegal(), nodep, - "sameHash function undefined (returns 0) for node under CFunc."); - // For identical nodes, the type should be the same thus - // dtypep should be the same too - m_lowerHash - = V3Hash(m_lowerHash, V3Hash(nodep->type() << 6, V3Hash(nodep->dtypep()))); - // Now update m_lowerHash for our children's (and next children) contributions - iterateChildren(nodep); - // Store the hash value - nodep->user4(m_lowerHash.fullValue()); - // UINFO(9, " hashnode "<(nodep)); - } - V3Hash finalHash() const { return m_lowerHash; } - virtual ~HashedVisitor() override = default; -}; - -//###################################################################### -// Hashed class functions - -V3Hash V3Hashed::uncachedHash(const AstNode* nodep) { - HashedVisitor visitor(nodep); - return visitor.finalHash(); -} - -V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) { - hash(nodep); - return m_hashMmap.emplace(nodeHash(nodep), nodep); -} - -void V3Hashed::hash(AstNode* nodep) { - UINFO(8, " hashI " << nodep << endl); - if (!nodep->user4p()) { HashedVisitor visitor(nodep); } -} - -bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) { - UASSERT_OBJ(node1p->user4p(), node1p, "Called isIdentical on non-hashed nodes"); - UASSERT_OBJ(node2p->user4p(), node2p, "Called isIdentical on non-hashed nodes"); - return (node1p->user4p() == node2p->user4p() // Same hash - && node1p->sameTree(node2p)); -} - -void V3Hashed::erase(iterator it) { - AstNode* nodep = iteratorNodep(it); - UINFO(8, " erase " << nodep << endl); - UASSERT_OBJ(nodep->user4p(), nodep, "Called removeNode on non-hashed node"); - m_hashMmap.erase(it); - nodep->user4p(nullptr); // So we don't allow removeNode again -} - -void V3Hashed::check() { - for (const auto& itr : *this) { - AstNode* nodep = itr.second; - UASSERT_OBJ(nodep->user4p(), nodep, "V3Hashed check failed, non-hashed node"); - } -} - -void V3Hashed::dumpFilePrefixed(const string& nameComment, bool tree) { - if (v3Global.opt.dumpTree()) dumpFile(v3Global.debugFilename(nameComment) + ".hash", tree); -} - -void V3Hashed::dumpFile(const string& filename, bool tree) { - const std::unique_ptr logp(V3File::new_ofstream(filename)); - if (logp->fail()) v3fatal("Can't write " << filename); - - std::unordered_map dist; - - V3Hash lasthash; - int num_in_bucket = 0; - for (HashMmap::iterator it = begin(); true; ++it) { - if (it == end() || lasthash != it->first) { - if (it != end()) lasthash = it->first; - if (num_in_bucket) { - if (dist.find(num_in_bucket) == dist.end()) { - dist.emplace(num_in_bucket, 1); - } else { - ++dist[num_in_bucket]; - } - } - num_in_bucket = 0; - } - if (it == end()) break; - num_in_bucket++; - } - *logp << "\n*** STATS:\n\n"; - *logp << " #InBucket Occurrences\n"; - for (const auto& i : dist) { - *logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << '\n'; - } - - *logp << "\n*** Dump:\n\n"; - for (const auto& itr : *this) { - if (lasthash != itr.first) { - lasthash = itr.first; - *logp << " " << itr.first << '\n'; - } - *logp << "\t" << itr.second << '\n'; - // Dumping the entire tree may make nearly N^2 sized dumps, - // because the nodes under this one may also be in the hash table! - if (tree) itr.second->dumpTree(*logp, " "); - } -} - -V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep, V3HashedUserSame* checkp) { - UINFO(8, " findD " << nodep << endl); - UASSERT_OBJ(nodep->user4p(), nodep, "Called findDuplicate on non-hashed node"); - std::pair eqrange - = mmap().equal_range(nodeHash(nodep)); - for (HashMmap::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) { - AstNode* node2p = eqit->second; - if (nodep != node2p && (!checkp || checkp->isSame(nodep, node2p)) - && sameNodes(nodep, node2p)) { - return eqit; - } - } - return end(); -} diff --git a/src/V3Hashed.h b/src/V3Hashed.h deleted file mode 100644 index 07bdcb7d4..000000000 --- a/src/V3Hashed.h +++ /dev/null @@ -1,92 +0,0 @@ -// -*- mode: C++; c-file-style: "cc-mode" -*- -//************************************************************************* -// DESCRIPTION: Verilator: Hash AST trees to find duplicates -// -// Code available from: https://verilator.org -// -//************************************************************************* -// -// Copyright 2005-2021 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_V3HASHED_H_ -#define VERILATOR_V3HASHED_H_ -#include "config_build.h" -#include "verilatedos.h" - -#include "V3Error.h" -#include "V3Ast.h" - -//============================================================================ - -class VHashedBase VL_NOT_FINAL { -public: - // CONSTRUCTORS - VHashedBase() = default; - ~VHashedBase() = default; - - // METHODS - VL_DEBUG_FUNC; // Declare debug() -}; - -//============================================================================ - -struct V3HashedUserSame { - // Functor for V3Hashed::findDuplicate - virtual bool isSame(AstNode*, AstNode*) = 0; - V3HashedUserSame() = default; - virtual ~V3HashedUserSame() = default; -}; - -class V3Hashed final : public VHashedBase { - // NODE STATE - // AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) - AstUser4InUse m_inuser4; - - // TYPES -public: - using HashMmap = std::multimap; - using iterator = HashMmap::iterator; - -private: - // MEMBERS - HashMmap m_hashMmap; // hashvalue -> nodes with that hash - -public: - // CONSTRUCTORS - V3Hashed() { clear(); } - ~V3Hashed() = default; - - // ACCESSORS - HashMmap& mmap() { return m_hashMmap; } // Return map for iteration - iterator begin() { return m_hashMmap.begin(); } - iterator end() { return m_hashMmap.end(); } - - // METHODS - void clear() { - m_hashMmap.clear(); - AstNode::user4ClearTree(); - } - void check(); // Check assertions on structure - // Hash the node, and insert into map. Return iterator to inserted - iterator hashAndInsert(AstNode* nodep); - static void hash(AstNode* nodep); // Only hash the node - // After hashing, and tell if identical - static bool sameNodes(AstNode* node1p, AstNode* node2p); - void erase(iterator it); // Remove node from structures - // Return duplicate in hash, if any, with optional user check for sameness - iterator findDuplicate(AstNode* nodep, V3HashedUserSame* checkp = nullptr); - AstNode* iteratorNodep(iterator it) { return it->second; } - void dumpFile(const string& filename, bool tree); - void dumpFilePrefixed(const string& nameComment, bool tree = false); - static V3Hash nodeHash(AstNode* nodep) { return V3Hash(nodep->user4p()); } - // Hash of the nodep tree, without caching in user4. - static V3Hash uncachedHash(const AstNode* nodep); -}; - -#endif // Guard diff --git a/src/V3Hasher.cpp b/src/V3Hasher.cpp new file mode 100644 index 000000000..625e923a3 --- /dev/null +++ b/src/V3Hasher.cpp @@ -0,0 +1,481 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: AstNode hash computation +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 "verilatedos.h" + +#include "V3Hasher.h" + +#include + +//###################################################################### +// Visitor that computes node hashes + +class HasherVisitor final : public AstNVisitor { +private: + // NODE STATE + // AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) + // AstUser4InUse in V3Hasher.h + + // STATE + V3Hash m_hash; // Hash value accumulator + const bool m_cacheInUser4; // Use user4 to cache each V3Hash? + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + V3Hash hashNodeAndIterate(AstNode* nodep, bool hashDType, bool hashChildren, + std::function&& f) { + if (m_cacheInUser4 && nodep->user4()) { + return V3Hash(nodep->user4()); + } else { + VL_RESTORER(m_hash); + // Reset accumulator + m_hash = V3Hash(nodep->type()); // Node type + f(); // Node specific hash + if (hashDType && nodep != nodep->dtypep()) iterateNull(nodep->dtypep()); // Node dtype + if (hashChildren) iterateChildrenConst(nodep); // Children + if (m_cacheInUser4) nodep->user4(m_hash.value()); + return m_hash; + } + } + + // VISITORS + + constexpr static bool HASH_DTYPE = true; + constexpr static bool HASH_CHILDREN = true; + + // Each visitor below contributes to the hash any node specific content + // that is not dependent on either of the following, as these are + // included by default by hashNode: + // - Node type (as given by AstNode::type()) + // - Node dtype (unless !hashDType) + // - child nodes (unless !hashChildren) + // + // The hash must be stable, which means in particular it cannot rely on + // pointer values, or any other value that might differ between separate + // invocations of Verilator over the same design. + // + // Note there is a circularity problem where some child nodes can back + // to their ancestral nodes via member pointers, which can lead to an + // infinite traversal. To break this, nodes that are subject to such + // referencing and represent code which can reasonably be assumed not to + // be equivalent to any other code, are hashed either by name (e.g.: + // AstNodeModule), or by unique identifier (e.g.: AstNodeUOrStructDType). + + //------------------------------------------------------------ + // AstNode - Warns to help find missing cases + + virtual void visit(AstNode* nodep) override { +#if VL_DEBUG + UINFO(0, "%Warning: Hashing node as AstNode: " << nodep); +#endif + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + + //------------------------------------------------------------ + // AstNodeDType + virtual void visit(AstNodeArrayDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + iterateNull(nodep->virtRefDTypep()); + m_hash += nodep->left(); + m_hash += nodep->right(); + }); + } + virtual void visit(AstNodeUOrStructDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, false, [=]() { // + m_hash += nodep->uniqueNum(); + }); + } + virtual void visit(AstParamTypeDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + m_hash += nodep->varType(); + }); + } + virtual void visit(AstMemberDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstDefImplicitDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->uniqueNum(); + }); + } + virtual void visit(AstAssocArrayDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + iterateNull(nodep->virtRefDTypep()); + iterateNull(nodep->virtRefDType2p()); + }); + } + virtual void visit(AstDynArrayDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->virtRefDTypep()); + }); + } + virtual void visit(AstUnsizedArrayDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->virtRefDTypep()); + }); + } + virtual void visit(AstBasicDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + m_hash += nodep->keyword(); + m_hash += nodep->nrange().left(); + m_hash += nodep->nrange().right(); + }); + } + virtual void visit(AstConstDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + iterateNull(nodep->virtRefDTypep()); + }); + } + virtual void visit(AstClassRefDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->classp()); + }); + } + virtual void visit(AstIfaceRefDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->cellp()); + }); + } + virtual void visit(AstQueueDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->virtRefDTypep()); + }); + } + virtual void visit(AstRefDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->typedefp()); + iterateNull(nodep->refDTypep()); + }); + } + virtual void visit(AstVoidDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstEnumDType* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, false, [=]() { // + m_hash += nodep->uniqueNum(); + }); + } + + //------------------------------------------------------------ + // AstNodeMath + virtual void visit(AstNodeMath* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstConst* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->num().toHash(); + }); + } + virtual void visit(AstNullCheck* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstCCast* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->size(); + }); + } + virtual void visit(AstVarRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + if (nodep->varScopep()) { + iterateNull(nodep->varScopep()); + } else { + iterateNull(nodep->varp()); + m_hash += nodep->hiernameToProt(); + } + }); + } + virtual void visit(AstVarXRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + iterateNull(nodep->varp()); + m_hash += nodep->dotted(); + }); + } + virtual void visit(AstMemberSel* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstFScanF* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + virtual void visit(AstSScanF* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + virtual void visit(AstTestPlusArgs* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + + //------------------------------------------------------------ + // AstNodeStmt + virtual void visit(AstNodeStmt* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstNodeText* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + virtual void visit(AstNodeCCall* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->funcp()); + }); + } + virtual void visit(AstNodeFTaskRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { + iterateNull(nodep->taskp()); + iterateNull(nodep->classOrPackagep()); + }); + } + virtual void visit(AstCMethodHard* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstCoverInc* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->declp()); + }); + } + virtual void visit(AstDisplay* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->displayType(); + }); + } + virtual void visit(AstMonitorOff* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->off(); + }); + } + virtual void visit(AstJumpGo* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->labelp()); + }); + } + virtual void visit(AstTraceInc* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + iterateNull(nodep->declp()); + }); + } + virtual void visit(AstNodeCoverOrAssert* nodep) override { + m_hash += hashNodeAndIterate(nodep, false, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + + //------------------------------------------------------------ + // AstNode direct descendents + virtual void visit(AstNodeRange* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstNodeModule* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() { + m_hash += nodep->origName(); + m_hash += nodep->hierName(); + }); + } + virtual void visit(AstNodePreSel* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstClassExtends* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstSelLoopVars* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstDefParam* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstArg* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstParseRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->expect(); + m_hash += nodep->name(); + }); + } + virtual void visit(AstClassOrPackageRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + iterateNull(nodep->classOrPackageNodep()); + }); + } + virtual void visit(AstSenItem* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->edgeType(); + }); + } + virtual void visit(AstSenTree* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstSFormatF* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->text(); + }); + } + virtual void visit(AstElabDisplay* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->displayType(); + }); + } + virtual void visit(AstInitItem* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstInitArray* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstPragma* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->pragType(); + }); + } + virtual void visit(AstAttrOf* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->attrType(); + }); + } + virtual void visit(AstNodeFile* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstCFunc* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstVar* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + m_hash += nodep->varType(); + }); + } + virtual void visit(AstScope* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, false, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->aboveScopep()); + }); + } + virtual void visit(AstVarScope* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + iterateNull(nodep->varp()); + iterateNull(nodep->scopep()); + }); + } + virtual void visit(AstEnumItem* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstTypedef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstTypedefFwd* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstActive* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + iterateNull(nodep->sensesp()); + }); + } + virtual void visit(AstCell* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->modp()); + }); + } + virtual void visit(AstCellInline* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->scopep()); + }); + } + virtual void visit(AstNodeFTask* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstModport* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstModportVarRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->varp()); + }); + } + virtual void visit(AstModportFTaskRef* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + iterateNull(nodep->ftaskp()); + }); + } + virtual void visit(AstNodeProcedure* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() {}); + } + virtual void visit(AstNodeBlock* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { // + m_hash += nodep->name(); + }); + } + virtual void visit(AstPin* nodep) override { + m_hash += hashNodeAndIterate(nodep, HASH_DTYPE, HASH_CHILDREN, [=]() { + m_hash += nodep->name(); + m_hash += nodep->pinNum(); + }); + } + +public: + // CONSTRUCTORS + explicit HasherVisitor(AstNode* nodep) + : m_cacheInUser4{true} { + iterate(nodep); + } + explicit HasherVisitor(const AstNode* nodep) + : m_cacheInUser4{false} { + iterate(const_cast(nodep)); + } + V3Hash finalHash() const { return m_hash; } + virtual ~HasherVisitor() override = default; +}; + +//###################################################################### +// V3Hasher methods + +V3Hash V3Hasher::operator()(AstNode* nodep) const { + if (!nodep->user4()) { HasherVisitor visitor(nodep); } + return V3Hash(nodep->user4()); +} + +V3Hash V3Hasher::uncachedHash(const AstNode* nodep) { + HasherVisitor visitor(nodep); + return visitor.finalHash(); +} diff --git a/src/V3Hasher.h b/src/V3Hasher.h new file mode 100644 index 000000000..6207515f1 --- /dev/null +++ b/src/V3Hasher.h @@ -0,0 +1,52 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Hash AST trees to find duplicates +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2005-2021 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 +// +//************************************************************************* +// +// V3Hasher handles computation of AstNode hashes +// +//************************************************************************* + +#ifndef VERILATOR_V3HASHER_H_ +#define VERILATOR_V3HASHER_H_ +#include "config_build.h" +#include "verilatedos.h" + +#include "V3Error.h" +#include "V3Ast.h" +#include "V3Hash.h" + +//============================================================================ + +class V3Hasher final { + // NODE STATE + // AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) + AstUser4InUse m_inuser4; + +public: + // CONSTRUCTORS + V3Hasher() = default; + ~V3Hasher() = default; + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + // Compute hash of node. This method caches the hash in the node's user4(). + V3Hash operator()(AstNode* nodep) const; + + // Compute hash of node, without caching in user4. + static V3Hash uncachedHash(const AstNode* nodep); +}; + +#endif // Guard diff --git a/src/V3Number.cpp b/src/V3Number.cpp index b6bd7937b..6abe9d4ae 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -24,6 +24,7 @@ #include #include #include +#include constexpr int MAX_SPRINTF_DOUBLE_SIZE = 1100; // Maximum characters with a sprintf %e/%f/%g (really 1079) @@ -883,7 +884,11 @@ string V3Number::toString() const { return str; } -uint32_t V3Number::toHash() const { return m_value[0]; } +V3Hash V3Number::toHash() const { + V3Hash hash(m_width); + for (int i = 0; i < words(); ++i) { hash += m_value[i]; } + return hash; +} uint32_t V3Number::edataWord(int eword) const { UASSERT(!isFourState(), "edataWord with 4-state " << *this); @@ -1526,11 +1531,8 @@ bool V3Number::isCaseEq(const V3Number& rhs) const { if (isString()) return toString() == rhs.toString(); if (isDouble()) return toDouble() == rhs.toDouble(); if (this->width() != rhs.width()) return false; - - for (int bit = 0; bit < std::max(this->width(), rhs.width()); bit++) { - if (this->bitIs(bit) != rhs.bitIs(bit)) return false; - } - return true; + if (m_value != rhs.m_value) return false; + return m_valueX == rhs.m_valueX; } V3Number& V3Number::opCaseEq(const V3Number& lhs, const V3Number& rhs) { @@ -1759,13 +1761,17 @@ V3Number& V3Number::opMul(const V3Number& lhs, const V3Number& rhs) { opCleanThis(); // Mult produces extra bits in result } else { for (int lword = 0; lword < lhs.words(); lword++) { + const vluint64_t lwordval = static_cast(lhs.m_value[lword]); + if (lwordval == 0) continue; for (int rword = 0; rword < rhs.words(); rword++) { - vluint64_t mul = static_cast(lhs.m_value[lword]) - * static_cast(rhs.m_value[rword]); + const vluint64_t rwordval = static_cast(rhs.m_value[rword]); + if (rwordval == 0) continue; + vluint64_t mul = lwordval * rwordval; for (int qword = lword + rword; qword < this->words(); qword++) { mul += static_cast(m_value[qword]); m_value[qword] = (mul & 0xffffffffULL); mul = (mul >> 32ULL) & 0xffffffffULL; + if (mul == 0) break; } } } diff --git a/src/V3Number.h b/src/V3Number.h index ab1bc4dd2..fd0f41f93 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -21,6 +21,7 @@ #include "verilatedos.h" #include "V3Error.h" +#include "V3Hash.h" #include #include @@ -298,7 +299,7 @@ public: string toDecimalS() const; // return ASCII signed decimal number string toDecimalU() const; // return ASCII unsigned decimal number double toDouble() const; - uint32_t toHash() const; + V3Hash toHash() const; uint32_t edataWord(int eword) const; uint8_t dataByte(int byte) const; uint32_t countBits(const V3Number& ctrl) const; diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp new file mode 100644 index 000000000..dd26b0846 --- /dev/null +++ b/src/V3OptionParser.cpp @@ -0,0 +1,232 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Command line option parser +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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 V3OPTION_PARSER_NO_VOPTION_BOOL +#include "V3Global.h" +#include "V3Options.h" +#endif +#include "V3Error.h" +#include "V3OptionParser.h" +#include "V3String.h" + +//###################################################################### +// V3OptionParser::Impl +struct V3OptionParser::Impl { + // TYPES + + // Setting for isOnOffAllowed() and isPartialMatchAllowed() + enum class en : uint8_t { + NONE, // "-opt" + ONOFF, // "-opt" and "-no-opt" + VALUE // "-opt val" + }; + // Base class of actual action classes + template + class ActionBase VL_NOT_FINAL : public ActionIfs { + bool m_undocumented = false; // This option is not documented + public: + virtual bool isValueNeeded() const override final { return MODE == en::VALUE; } + virtual bool isOnOffAllowed() const override final { return MODE == en::ONOFF; } + virtual bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; } + virtual bool isUndocumented() const override { return m_undocumented; } + virtual void undocumented() override { m_undocumented = true; } + }; + + // Actual action classes + template class ActionSet; // "-opt" for bool-ish, "-opt val" for int and string + template class ActionOnOff; // "-opt" and "-no-opt" for bool-ish + class ActionCbCall; // Callback without argument for "-opt" + class ActionCbOnOff; // Callback for "-opt" and "-no-opt" + template class ActionCbVal; // Callback for "-opt val" + class ActionCbPartialMatch; // Callback "-O3" for "-O" + class ActionCbPartialMatchVal; // Callback "-debugi-V3Options 3" for "-debugi-" + + // MEMBERS + std::map> m_options; // All actions for option + bool m_isFinalized{false}; // Becomes after finalize() is called + VSpellCheck m_spellCheck; // Suggests closest option when not found +}; + +//###################################################################### +// Action classes in V3OptionParser::Impl + +#define V3OPTION_PARSER_DEF_ACT_CLASS(className, type, body, enType) \ + template <> class V3OptionParser::Impl::className final : public ActionBase { \ + type* m_valp; /* Pointer to a option variable*/ \ +\ + public: \ + explicit className(type* valp) \ + : m_valp(valp) {} \ + virtual void exec(const char* optp, const char* argp) override { body; } \ + } + +V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, bool, *m_valp = true, en::NONE); +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, VOptionBool, m_valp->setTrueOrFalse(true), en::NONE); +#endif +V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, int, *m_valp = std::atoi(argp), en::VALUE); +V3OPTION_PARSER_DEF_ACT_CLASS(ActionSet, string, *m_valp = argp, en::VALUE); + +V3OPTION_PARSER_DEF_ACT_CLASS(ActionOnOff, bool, *m_valp = !hasPrefixNo(optp), en::ONOFF); +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +V3OPTION_PARSER_DEF_ACT_CLASS(ActionOnOff, VOptionBool, m_valp->setTrueOrFalse(!hasPrefixNo(optp)), + en::ONOFF); +#endif +#undef V3OPTION_PARSER_DEF_ACT_CLASS + +#define V3OPTION_PARSER_DEF_ACT_CB_CLASS(className, funcType, body, ...) \ + class V3OptionParser::Impl::className final : public ActionBase<__VA_ARGS__> { \ + std::function m_cb; /* Callback function */ \ +\ + public: \ + using CbType = std::function; \ + explicit className(CbType cb) \ + : m_cb(std::move(cb)) {} \ + virtual void exec(const char* optp, const char* argp) override { body; } \ + } + +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbCall, void(void), m_cb(), en::NONE); +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbOnOff, void(bool), m_cb(!hasPrefixNo(optp)), en::ONOFF); +template <> +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbVal, void(int), m_cb(std::atoi(argp)), en::VALUE); +template <> +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbVal, void(const char*), m_cb(argp), + en::VALUE); +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbPartialMatch, void(const char*), m_cb(optp), en::NONE, + true); +V3OPTION_PARSER_DEF_ACT_CB_CLASS(ActionCbPartialMatchVal, void(const char*, const char*), + m_cb(optp, argp), en::VALUE, true); + +#undef V3OPTION_PARSER_DEF_ACT_CB_CLASS + +//###################################################################### +// Member functions of V3OptionParser + +V3OptionParser::ActionIfs* V3OptionParser::find(const char* optp) { + auto it = m_pimpl->m_options.find(optp); + if (it != m_pimpl->m_options.end()) return it->second.get(); + for (auto&& act : m_pimpl->m_options) { + if (act.second->isOnOffAllowed()) { // Find starts with "-no" + const char* const nop = std::strncmp(optp, "-no", 3) ? nullptr : (optp + 3); + if (nop && (act.first == nop || act.first == (string{"-"} + nop))) { + return act.second.get(); + } + } else if (act.second->isPartialMatchAllowed()) { + if (!std::strncmp(optp, act.first.c_str(), act.first.length())) { + return act.second.get(); + } + } + } + return nullptr; +} + +template +V3OptionParser::ActionIfs& V3OptionParser::add(const std::string& opt, ARG arg) { + UASSERT(!m_pimpl->m_isFinalized, "Cannot add after finalize() is called"); + std::unique_ptr act{new ACT{std::move(arg)}}; + UASSERT(opt.size() >= 2, opt << " is too short"); + UASSERT(opt[0] == '-' || opt[0] == '+', opt << " does not start with either '-' or '+'"); + UASSERT(!(opt[0] == '-' && opt[1] == '-'), "Option must have single '-', but " << opt); + const auto insertedResult = m_pimpl->m_options.emplace(opt, std::move(act)); + UASSERT(insertedResult.second, opt << " is already registered"); + return *insertedResult.first->second; +} + +bool V3OptionParser::hasPrefixNo(const char* strp) { + UASSERT(strp[0] == '-', strp << " does not start with '-'"); + if (strp[1] == '-') ++strp; + return std::strncmp(strp, "-no", 3) == 0; +} + +int V3OptionParser::parse(int idx, int argc, char* argv[]) { + UASSERT(m_pimpl->m_isFinalized, "finalize() must be called before parse()"); + const char* optp = argv[idx]; + if (optp[0] == '-' && optp[1] == '-') ++optp; + ActionIfs* actp = find(optp); + if (!actp) return 0; + if (!actp->isValueNeeded()) { + actp->exec(optp, nullptr); + return 1; + } else if (idx + 1 < argc) { + actp->exec(optp, argv[idx + 1]); + return 2; + } + return 0; +} + +string V3OptionParser::getSuggestion(const char* str) const { + return m_pimpl->m_spellCheck.bestCandidateMsg(str); +} + +void V3OptionParser::addSuggestionCandidate(const string& s) { + m_pimpl->m_spellCheck.pushCandidate(s); +} + +void V3OptionParser::finalize() { + UASSERT(!m_pimpl->m_isFinalized, "finalize() must not be called twice"); + for (auto&& opt : m_pimpl->m_options) { + if (opt.second->isUndocumented()) continue; + m_pimpl->m_spellCheck.pushCandidate(opt.first); + if (opt.second->isOnOffAllowed()) m_pimpl->m_spellCheck.pushCandidate("-no" + opt.first); + } + m_pimpl->m_isFinalized = true; +} + +V3OptionParser::V3OptionParser() + : m_pimpl{new Impl{}} {} + +V3OptionParser::~V3OptionParser() = default; + +//###################################################################### +// Member functions of V3OptionParser::AppendHelper + +#define V3OPTION_PARSER_DEF_OP(actKind, argType, actType) \ + V3OptionParser::ActionIfs& V3OptionParser::AppendHelper::operator()( \ + const char* optp, actKind, argType arg) const { \ + return m_parser.add(optp, arg); \ + } +V3OPTION_PARSER_DEF_OP(Set, bool*, ActionSet) +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +V3OPTION_PARSER_DEF_OP(Set, VOptionBool*, ActionSet) +#endif +V3OPTION_PARSER_DEF_OP(Set, int*, ActionSet) +V3OPTION_PARSER_DEF_OP(Set, string*, ActionSet) +V3OPTION_PARSER_DEF_OP(OnOff, bool*, ActionOnOff) +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +V3OPTION_PARSER_DEF_OP(OnOff, VOptionBool*, ActionOnOff) +#endif +V3OPTION_PARSER_DEF_OP(CbCall, Impl::ActionCbCall::CbType, ActionCbCall) +V3OPTION_PARSER_DEF_OP(CbOnOff, Impl::ActionCbOnOff::CbType, ActionCbOnOff) +V3OPTION_PARSER_DEF_OP(CbVal, Impl::ActionCbVal::CbType, ActionCbVal) +V3OPTION_PARSER_DEF_OP(CbVal, Impl::ActionCbVal::CbType, ActionCbVal) +#undef V3OPTION_PARSER_DEF_OP + +V3OptionParser::ActionIfs& +V3OptionParser::AppendHelper::operator()(const char* optp, CbPartialMatch, + Impl::ActionCbPartialMatch::CbType cb) const { + const size_t prefixLen = std::strlen(optp); + auto wrap = [prefixLen, cb](const char* optp) { cb(optp + prefixLen); }; + return m_parser.add(optp, std::move(wrap)); +} + +V3OptionParser::ActionIfs& +V3OptionParser::AppendHelper::operator()(const char* optp, CbPartialMatchVal, + Impl::ActionCbPartialMatchVal::CbType cb) const { + const size_t prefixLen = std::strlen(optp); + auto wrap + = [prefixLen, cb](const char* optp, const char* argp) { cb(optp + prefixLen, argp); }; + return m_parser.add(optp, std::move(wrap)); +} diff --git a/src/V3OptionParser.h b/src/V3OptionParser.h new file mode 100644 index 000000000..a42c5fca2 --- /dev/null +++ b/src/V3OptionParser.h @@ -0,0 +1,157 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Command line option parser +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2021 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_V3OPTION_PARSER_H_ +#define VERILATOR_V3OPTION_PARSER_H_ + +#include "config_build.h" +#include "verilatedos.h" + +#include +#include +#include + +// Not to include V3Option.h here so that VlcMain or other executables can use this file easily. +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL +class VOptionBool; +#endif + +// Typycal usage would look as below. +// See also V3Options::parseOptsList() in V3Optoins.cpp for more detailed usage. +// +// V3OptionParser parser; +// V3OptionParser::AppendHelper DECL_OPTION{parser}; +// V3OPTION_PARSER_DECL_TAGS; +// +// DECL_OPPTION("-help", CbCall, []() { showHelp(); }); +// DECL_OPPTION("-some_opt", Set, &m_intMember}); +// parser.finalize(); +// for (int i = 1; i < argc;) { +// if (int consumed = parser.parse(i, argc, argv)) { +// i += consumed; +// } else { // error +// cerr << parser.getSuggestion(argv[i]) << endl; +// } +// } +// + +//###################################################################### +// V3 OptionParser + +class V3OptionParser final { +public: + // TYPES + class ActionIfs; + // Functor to register options to V3OptionParser + class AppendHelper; + struct Impl; + +private: + // MEMBERS + std::unique_ptr m_pimpl; + + // METHODS + ActionIfs* find(const char* optp); + template ActionIfs& add(const string& opt, ARG arg); + static bool hasPrefixNo(const char* strp); // Returns true if strp starts with "-no" + +public: + // METHODS + // Returns how many args are consumed. 0 means not match + int parse(int idx, int argc, char* argv[]); + // Find the most similar option + string getSuggestion(const char* str) const; + void addSuggestionCandidate(const string& s); + // Call this function after all options are registered. + void finalize(); + + // CONSTRUCTORS + V3OptionParser(); + ~V3OptionParser(); +}; + +class V3OptionParser::ActionIfs VL_NOT_FINAL { +public: + virtual ~ActionIfs() = default; + virtual bool isValueNeeded() const = 0; // Need val of "-opt val" + virtual bool isOnOffAllowed() const = 0; // true if "-no-opt" is allowd + virtual bool isPartialMatchAllowed() const = 0; // true if "-Wno-" matches "-Wno-fatal" + virtual bool isUndocumented() const = 0; // Will not be suggested in typo + // Set a value or run callback + virtual void exec(const char* optp, const char* valp) = 0; + // Mark this option undocumented. (Exclude this option from suggestion list). + virtual void undocumented() = 0; +}; + +// A helper class to register options +class V3OptionParser::AppendHelper final { +public: + // TYPES + // Tag to specify which operator() to call + struct Set {}; // For ActionSet + struct OnOff {}; // For ActionOnOff + struct CbCall {}; // For ActionCbCall + struct CbOnOff {}; // For ActionOnOff + struct CbVal {}; // For ActionCbVal + struct CbPartialMatch {}; // For ActionCbPartialMatch + struct CbPartialMatchVal {}; // For ActionCbPartialMatchVal + +private: + // MEMBERS + V3OptionParser& m_parser; // The actual option registory + +public: + // METHODS + ActionIfs& operator()(const char* optp, Set, bool*) const; +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL + ActionIfs& operator()(const char* optp, Set, VOptionBool*) const; +#endif + ActionIfs& operator()(const char* optp, Set, int*) const; + ActionIfs& operator()(const char* optp, Set, string*) const; + + ActionIfs& operator()(const char* optp, OnOff, bool*) const; +#ifndef V3OPTION_PARSER_NO_VOPTION_BOOL + ActionIfs& operator()(const char* optp, OnOff, VOptionBool*) const; +#endif + + ActionIfs& operator()(const char* optp, CbCall, std::function) const; + ActionIfs& operator()(const char* optp, CbOnOff, std::function) const; + ActionIfs& operator()(const char* optp, CbVal, std::function) const; + ActionIfs& operator()(const char* optp, CbVal, std::function) const; + + ActionIfs& operator()(const char* optp, CbPartialMatch, + std::function) const; + ActionIfs& operator()(const char* optp, CbPartialMatchVal, + std::function) const; + + // CONSTRUCTORS + explicit AppendHelper(V3OptionParser& parser) + : m_parser(parser) {} +}; + +#define V3OPTION_PARSER_DECL_TAGS \ + const auto Set VL_ATTR_UNUSED = V3OptionParser::AppendHelper::Set{}; \ + const auto OnOff VL_ATTR_UNUSED = V3OptionParser::AppendHelper::OnOff{}; \ + const auto CbCall VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbCall{}; \ + const auto CbOnOff VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbOnOff{}; \ + const auto CbVal VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbVal{}; \ + const auto CbPartialMatch VL_ATTR_UNUSED = V3OptionParser::AppendHelper::CbPartialMatch{}; \ + const auto CbPartialMatchVal VL_ATTR_UNUSED \ + = V3OptionParser::AppendHelper::CbPartialMatchVal {} + +//###################################################################### + +#endif // guard diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 244d890d0..49a65e5ac 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -19,9 +19,9 @@ #include "V3Global.h" #include "V3Ast.h" -#include "V3String.h" #include "V3Os.h" #include "V3Options.h" +#include "V3OptionParser.h" #include "V3Error.h" #include "V3File.h" #include "V3PreShell.h" @@ -37,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -106,226 +105,6 @@ public: ~V3OptionsImp() = default; }; -//###################################################################### -// V3 OptionParser - -class V3OptionsParser final { -public: - // TYPES - class ActionIfs VL_NOT_FINAL { - public: - virtual ~ActionIfs() = default; - virtual bool isValueNeeded() const = 0; // Need val of "-opt val" - virtual bool isOnOffAllowed() const = 0; // true if "-no-opt" is allowd - virtual bool isPartialMatchAllowed() const = 0; // true if "-Wno-" matches "-Wno-fatal" - virtual bool isUndocumented() const = 0; // Will not be suggested in typo - // Set a value or run callback - virtual void exec(const char* optp, const char* valp) = 0; - virtual void undocumented() = 0; - }; - enum class en { // Setting for isOnOffAllowed() and isPartialMatchAllowed() - NONE, // "-opt" - ONOFF, // "-opt" and "-no-opt" - VALUE // "-opt val" - }; - // Base class of actual action classes - template - class ActionBase VL_NOT_FINAL : public ActionIfs { - bool m_undocumented = false; // This option is not documented - public: - virtual bool isValueNeeded() const override final { return MODE == en::VALUE; } - virtual bool isOnOffAllowed() const override final { return MODE == en::ONOFF; } - virtual bool isPartialMatchAllowed() const override final { return ALLOW_PARTIAL_MATCH; } - virtual bool isUndocumented() const override { return m_undocumented; } - virtual void undocumented() override { m_undocumented = true; } - }; - // Actual action classes - template class ActionSet; // "-opt" for bool-ish, "-opt val" for int and string - template class ActionOnOff; // "-opt" and "-no-opt" for bool-ish - class ActionCbCall; // Callback without argument for "-opt" - class ActionCbOnOff; // Callback for "-opt" and "-no-opt" - template class ActionCbVal; // Callback for "-opt val" - class ActionCbPartialMatch; // Callback "-O3" for "-O" - class ActionCbPartialMatchVal; // Callback "-debugi-V3Options 3" for "-debugi-" - - // Functor to register options to V3OptionsParser - struct AppendHelper; - -private: - // MEMBERS - std::map> m_options; // All actions for option - bool m_isFinalized{false}; // Becomes after finalize() is called - VSpellCheck m_spellCheck; // Suggests closest option when not found - - // METHODS - ActionIfs* find(const char* optp) { - auto it = m_options.find(optp); - if (it != m_options.end()) return it->second.get(); - for (auto&& act : m_options) { - if (act.second->isOnOffAllowed()) { // Find starts with "-no" - const char* const nop = std::strncmp(optp, "-no", 3) ? nullptr : (optp + 3); - if (nop && (act.first == nop || act.first == (string{"-"} + nop))) { - return act.second.get(); - } - } else if (act.second->isPartialMatchAllowed()) { - if (!std::strncmp(optp, act.first.c_str(), act.first.length())) { - return act.second.get(); - } - } - } - return nullptr; - } - template ActionIfs& add(const std::string& opt, ARG arg) { - UASSERT(!m_isFinalized, "Cannot add after finalize() is called"); - std::unique_ptr act{new ACT{std::move(arg)}}; - UASSERT(opt.size() >= 2, opt << " is too short"); - UASSERT(opt[0] == '-' || opt[0] == '+', opt << " does not start with either '-' or '+'"); - UASSERT(!(opt[0] == '-' && opt[1] == '-'), "Option must have single '-', but " << opt); - const auto insertedResult = m_options.emplace(opt, std::move(act)); - UASSERT(insertedResult.second, opt << " is already registered"); - return *insertedResult.first->second; - } - static bool hasPrefixNo(const char* strp) { // Returns true if strp starts with "-no" - UASSERT(strp[0] == '-', strp << " does not start with '-'"); - if (strp[1] == '-') ++strp; - return std::strncmp(strp, "-no", 3) == 0; - } - -public: - // METHODS - // Returns how many args are consumed. 0 means not match - int parse(int idx, int argc, char* argv[]) { - UASSERT(m_isFinalized, "finalize() must be called before parse()"); - const char* optp = argv[idx]; - if (optp[0] == '-' && optp[1] == '-') ++optp; - ActionIfs* actp = find(optp); - if (!actp) return 0; - if (!actp->isValueNeeded()) { - actp->exec(optp, nullptr); - return 1; - } else if (idx + 1 < argc) { - actp->exec(optp, argv[idx + 1]); - return 2; - } - return 0; - } - // Find the most similar option - string getSuggestion(const char* str) const { return m_spellCheck.bestCandidateMsg(str); } - void addSuggestionCandidate(const string& s) { m_spellCheck.pushCandidate(s); } - void finalize() { - UASSERT(!m_isFinalized, "finalize() must not be called twice"); - for (auto&& opt : m_options) { - if (opt.second->isUndocumented()) continue; - m_spellCheck.pushCandidate(opt.first); - if (opt.second->isOnOffAllowed()) m_spellCheck.pushCandidate("-no" + opt.first); - } - m_isFinalized = true; - } -}; - -#define V3OPTIONS_DEF_ACT_CLASS(className, type, body, enType) \ - template <> class V3OptionsParser::className final : public ActionBase { \ - type* m_valp; /* Pointer to a option variable*/ \ -\ - public: \ - explicit className(type* valp) \ - : m_valp(valp) {} \ - virtual void exec(const char* optp, const char* argp) override { body; } \ - } - -V3OPTIONS_DEF_ACT_CLASS(ActionSet, bool, *m_valp = true, en::NONE); -V3OPTIONS_DEF_ACT_CLASS(ActionSet, VOptionBool, m_valp->setTrueOrFalse(true), en::NONE); -V3OPTIONS_DEF_ACT_CLASS(ActionSet, int, *m_valp = std::atoi(argp), en::VALUE); -V3OPTIONS_DEF_ACT_CLASS(ActionSet, string, *m_valp = argp, en::VALUE); - -V3OPTIONS_DEF_ACT_CLASS(ActionOnOff, bool, *m_valp = !hasPrefixNo(optp), en::ONOFF); -V3OPTIONS_DEF_ACT_CLASS(ActionOnOff, VOptionBool, m_valp->setTrueOrFalse(!hasPrefixNo(optp)), - en::ONOFF); - -#undef V3OPTIONS_DEF_ACT_CLASS - -#define V3OPTIONS_DEF_ACT_CB_CLASS(className, funcType, body, ...) \ - class V3OptionsParser::className final : public ActionBase<__VA_ARGS__> { \ - std::function m_cb; /* Callback function */ \ -\ - public: \ - using CbType = std::function; \ - explicit className(CbType cb) \ - : m_cb(std::move(cb)) {} \ - virtual void exec(const char* optp, const char* argp) override { body; } \ - } - -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbCall, void(void), m_cb(), en::NONE); -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbOnOff, void(bool), m_cb(!hasPrefixNo(optp)), en::ONOFF); -template <> -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbVal, void(int), m_cb(std::atoi(argp)), en::VALUE); -template <> -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbVal, void(const char*), m_cb(argp), en::VALUE); -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbPartialMatch, void(const char*), m_cb(optp), en::NONE, true); -V3OPTIONS_DEF_ACT_CB_CLASS(ActionCbPartialMatchVal, void(const char*, const char*), - m_cb(optp, argp), en::VALUE, true); - -#undef V3OPTIONS_DEF_ACT_CB_CLASS - -// A helper class to register options -struct V3OptionsParser::AppendHelper final { - V3OptionsParser& m_parser; // The actual option registory - - // TYPES - // Tag to specify which operator() to call - struct Set {}; // For ActionSet - struct OnOff {}; // For ActionOnOff - struct CbCall {}; // For ActionCbCall - struct CbOnOff {}; // For ActionOnOff - struct CbVal {}; // For ActionCbVal - struct CbPartialMatch {}; // For ActionCbPartialMatch - struct CbPartialMatchVal {}; // For ActionCbPartialMatchVal - - // METHODS - -#define V3OPTIONS_DEF_OP(actKind, argType, actType) \ - ActionIfs& operator()(const char* optp, actKind, argType arg) const { \ - return m_parser.add(optp, arg); \ - } - V3OPTIONS_DEF_OP(Set, bool*, ActionSet) - V3OPTIONS_DEF_OP(Set, VOptionBool*, ActionSet) - V3OPTIONS_DEF_OP(Set, int*, ActionSet) - V3OPTIONS_DEF_OP(Set, string*, ActionSet) - V3OPTIONS_DEF_OP(OnOff, bool*, ActionOnOff) - V3OPTIONS_DEF_OP(OnOff, VOptionBool*, ActionOnOff) - V3OPTIONS_DEF_OP(CbCall, ActionCbCall::CbType, ActionCbCall) - V3OPTIONS_DEF_OP(CbOnOff, ActionCbOnOff::CbType, ActionCbOnOff) - V3OPTIONS_DEF_OP(CbVal, ActionCbVal::CbType, ActionCbVal) - V3OPTIONS_DEF_OP(CbVal, ActionCbVal::CbType, ActionCbVal) -#undef V3OPTIONS_DEF_OP - - // Syntax sugar to register a member function of V3Options directry - ActionIfs& operator()(const char* optp, CbVal, - std::pair arg) const { - auto cb = [arg](int v) { (arg.first->*arg.second)(v); }; - return m_parser.add>(optp, cb); - } - ActionIfs& operator()(const char* optp, CbVal, - std::pair arg) const { - auto cb = [arg](const string& v) { (arg.first->*arg.second)(v); }; - return m_parser.add>(optp, cb); - } - // Callback of partial match expects prefix to be removed, so wrap the given callback - ActionIfs& operator()(const char* optp, CbPartialMatch, - ActionCbPartialMatch::CbType cb) const { - const size_t prefixLen = std::strlen(optp); - auto wrap = [prefixLen, cb](const char* optp) { cb(optp + prefixLen); }; - return m_parser.add(optp, std::move(wrap)); - } - ActionIfs& operator()(const char* optp, CbPartialMatchVal, - ActionCbPartialMatchVal::CbType cb) const { - const size_t prefixLen = std::strlen(optp); - auto wrap - = [prefixLen, cb](const char* optp, const char* argp) { cb(optp + prefixLen, argp); }; - return m_parser.add(optp, std::move(wrap)); - } -}; - //###################################################################### // V3LangCode class functions @@ -1008,6 +787,10 @@ void V3Options::notify() { cmdfl->v3warn(E_UNSUPPORTED, "--main not usable with SystemC. Suggest see examples for sc_main()."); } + + if (coverage() && savable()) { + cmdfl->v3error("--coverage and --savable not supported together"); + } } //###################################################################### @@ -1112,20 +895,18 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char addArg(argv[i]); // -f's really should be inserted in the middle, but this is for debug } - V3OptionsParser parser; - const auto Set = V3OptionsParser::AppendHelper::Set{}; - const auto OnOff = V3OptionsParser::AppendHelper::OnOff{}; - const auto CbCall = V3OptionsParser::AppendHelper::CbCall{}; - const auto CbOnOff = V3OptionsParser::AppendHelper::CbOnOff{}; - const auto CbVal = V3OptionsParser::AppendHelper::CbVal{}; - const auto CbPartialMatch = V3OptionsParser::AppendHelper::CbPartialMatch{}; - const auto CbPartialMatchVal = V3OptionsParser::AppendHelper::CbPartialMatchVal{}; - V3OptionsParser::AppendHelper DECL_OPTION{parser}; + V3OptionParser parser; + V3OptionParser::AppendHelper DECL_OPTION{parser}; + V3OPTION_PARSER_DECL_TAGS; + + auto callStrSetter = [this](void (V3Options::*cbStr)(const string&)) { + return [this, cbStr](const string& v) { (this->*cbStr)(v); }; + }; // Usage // DECL_OPTION("-option", action, pointer_or_lambda); // action: one of Set, OnOff, CbCall, CbOnOff, CbVal, CbPartialMatch, and CbPartialMatchVal // Set : Set value to a variable, pointer_or_lambda must be a pointer to the - // variable. + // variable. // true is set to bool-ish variable when '-opt' is passed to verilator. // val is set to int and string variable when '-opt val' is passed. // OnOff : Set value to a bool-ish variable, pointer_or_lambda must be a pointer @@ -1138,7 +919,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char // CbVal : Call lambda or function that takes int or const char*. // "-opt val" is passed to verilator, val is passed to the lambda. // If a function to be called is a member of V3Options that only takes - // bool/const string&, {this, &V3Options::memberFunc} can be passed + // const string&, callStrSetter(&V3Options::memberFunc) can be passed // instead of lambda as a syntax sugar. // CbPartialMatch : Call lambda or function that takes remaining string. // e.g. DECL_OPTION("-opt-", CbPartialMatch, [](const char*optp) { cout << @@ -1201,14 +982,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-bin", Set, &m_bin); DECL_OPTION("-build", Set, &m_build); - DECL_OPTION("-CFLAGS", CbVal, {this, &V3Options::addCFlags}); + DECL_OPTION("-CFLAGS", CbVal, callStrSetter(&V3Options::addCFlags)); DECL_OPTION("-cc", CbCall, [this]() { m_outFormatOk = true; m_systemC = false; }); DECL_OPTION("-cdc", OnOff, &m_cdc); - DECL_OPTION("-clk", CbVal, {this, &V3Options::addClocker}); - DECL_OPTION("-no-clk", CbVal, {this, &V3Options::addNoClocker}); + DECL_OPTION("-clk", CbVal, callStrSetter(&V3Options::addClocker)); + DECL_OPTION("-no-clk", CbVal, callStrSetter(&V3Options::addNoClocker)); DECL_OPTION("-comp-limit-blocks", Set, &m_compLimitBlocks).undocumented(); DECL_OPTION("-comp-limit-members", Set, &m_compLimitMembers) @@ -1244,7 +1025,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-D", CbPartialMatch, [this](const char* valp) { addDefine(valp, false); }); DECL_OPTION("-debug", CbCall, [this]() { setDebugMode(3); }); - DECL_OPTION("-debugi", CbVal, {this, &V3Options::setDebugMode}); + DECL_OPTION("-debugi", CbVal, [this](int v) { setDebugMode(v); }); DECL_OPTION("-debugi-", CbPartialMatchVal, [this](const char* optp, const char* valp) { setDebugSrcLevel(optp, std::atoi(valp)); }); @@ -1279,6 +1060,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-E", Set, &m_preprocOnly); DECL_OPTION("-error-limit", CbVal, static_cast(&V3Error::errorLimit)); DECL_OPTION("-exe", OnOff, &m_exe); + DECL_OPTION("-expand-limit", CbVal, + [this](const char* valp) { m_expandLimit = std::atoi(valp); }); DECL_OPTION("-F", CbVal, [this, fl, &optdir](const char* valp) { parseOptsFile(fl, parseFileArg(optdir, valp), true); @@ -1320,7 +1103,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char }); DECL_OPTION("-inline-mult", Set, &m_inlineMult); - DECL_OPTION("-LDFLAGS", CbVal, {this, &V3Options::addLdLibs}); + DECL_OPTION("-LDFLAGS", CbVal, callStrSetter(&V3Options::addLdLibs)); auto setLang = [this, fl](const char* valp) { V3LangCode optval = V3LangCode(valp); if (optval.legal()) { @@ -1340,7 +1123,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char DECL_OPTION("-no-l2name", CbCall, [this]() { m_l2Name = ""; }).undocumented(); // Historical DECL_OPTION("-l2name", CbCall, [this]() { m_l2Name = "v"; }).undocumented(); // Historical - DECL_OPTION("-MAKEFLAGS", CbVal, {this, &V3Options::addMakeFlags}); + DECL_OPTION("-MAKEFLAGS", CbVal, callStrSetter(&V3Options::addMakeFlags)); DECL_OPTION("-MMD", OnOff, &m_makeDepend); DECL_OPTION("-MP", OnOff, &m_makePhony); DECL_OPTION("-Mdir", CbVal, [this](const char* valp) { @@ -1465,6 +1248,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char fl->v3warn(DEPRECATED, "Deprecated --no-relative-cfuncs, unnecessary with C++11."); }); DECL_OPTION("-relative-includes", OnOff, &m_relativeIncludes); + DECL_OPTION("-reloop-limit", CbVal, [this, fl](const char* valp) { + m_reloopLimit = std::atoi(valp); + if (m_reloopLimit < 2) { fl->v3error("--reloop-limit must be >= 2: " << valp); } + }); DECL_OPTION("-report-unoptflat", OnOff, &m_reportUnoptflat); DECL_OPTION("-rr", CbCall, []() {}); // Processed only in bin/verilator shell diff --git a/src/V3Options.h b/src/V3Options.h index 7cb64f2ea..dff879acf 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -285,6 +285,7 @@ private: int m_convergeLimit = 100; // main switch: --converge-limit int m_coverageMaxWidth = 256; // main switch: --coverage-max-width int m_dumpTree = 0; // main switch: --dump-tree + int m_expandLimit = 64; // main switch: --expand-limit int m_gateStmts = 100; // main switch: --gate-stmts int m_ifDepth = 0; // main switch: --if-depth int m_inlineMult = 2000; // main switch: --inline-mult @@ -295,6 +296,7 @@ private: int m_outputSplitCFuncs = -1; // main switch: --output-split-cfuncs int m_outputSplitCTrace = -1; // main switch: --output-split-ctrace int m_pinsBv = 65; // main switch: --pins-bv + int m_reloopLimit = 40; // main switch: --reloop-limit VOptionBool m_skipIdentical; // main switch: --skip-identical int m_threads = 0; // main switch: --threads (0 == --no-threads) int m_threadsMaxMTasks = 0; // main switch: --threads-max-mtasks @@ -481,6 +483,7 @@ public: int coverageMaxWidth() const { return m_coverageMaxWidth; } int dumpTree() const { return m_dumpTree; } bool dumpTreeAddrids() const { return m_dumpTreeAddrids; } + int expandLimit() const { return m_expandLimit; } int gateStmts() const { return m_gateStmts; } int ifDepth() const { return m_ifDepth; } int inlineMult() const { return m_inlineMult; } @@ -491,6 +494,7 @@ public: int outputSplitCFuncs() const { return m_outputSplitCFuncs; } int outputSplitCTrace() const { return m_outputSplitCTrace; } int pinsBv() const { return m_pinsBv; } + int reloopLimit() const { return m_reloopLimit; } VOptionBool skipIdentical() const { return m_skipIdentical; } int threads() const { return m_threads; } int threadsMaxMTasks() const { return m_threadsMaxMTasks; } diff --git a/src/V3Order.cpp b/src/V3Order.cpp index b354a157d..9baa69c7a 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -1723,50 +1723,73 @@ void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d AstActive* OrderVisitor::processMoveOneLogic(const OrderLogicVertex* lvertexp, AstCFunc*& newFuncpr, int& newStmtsr) { AstActive* activep = nullptr; - AstScope* scopep = lvertexp->scopep(); - AstSenTree* domainp = lvertexp->domainp(); + AstScope* const scopep = lvertexp->scopep(); + AstSenTree* const domainp = lvertexp->domainp(); AstNode* nodep = lvertexp->nodep(); - AstNodeModule* modp = VN_CAST(scopep->user1p(), NodeModule); // Stashed by visitor func + AstNodeModule* const modp = VN_CAST(scopep->user1p(), NodeModule); // Stashed by visitor func UASSERT(modp, "nullptr"); if (VN_IS(nodep, SenTree)) { // Just ignore sensitivities, we'll deal with them when we move statements that need them } else { // Normal logic - // Make or borrow a CFunc to contain the new statements - if (v3Global.opt.profCFuncs() - || (v3Global.opt.outputSplitCFuncs() - && v3Global.opt.outputSplitCFuncs() < newStmtsr)) { - // Put every statement into a unique function to ease profiling or reduce function size - newFuncpr = nullptr; - } - if (!newFuncpr && domainp != m_deleteDomainp) { - string name = cfuncName(modp, domainp, scopep, nodep); - newFuncpr = new AstCFunc(nodep->fileline(), name, scopep); - newFuncpr->argTypes(EmitCBaseVisitor::symClassVar()); - newFuncpr->symProlog(true); - newStmtsr = 0; - if (domainp->hasInitial() || domainp->hasSettle()) newFuncpr->slow(true); - scopep->addActivep(newFuncpr); - // Where will we be adding the call? - activep = new AstActive(nodep->fileline(), name, domainp); - // Add a top call to it - AstCCall* callp = new AstCCall(nodep->fileline(), newFuncpr); - callp->argTypes("vlSymsp"); - activep->addStmtsp(callp); - UINFO(6, " New " << newFuncpr << endl); + // Move the logic into a CFunc + nodep->unlinkFrBack(); + + // Process procedures per statement (unless profCFuncs), so we can split CFuncs within + // procedures. Everything else is handled in one go + AstNodeProcedure* const procp = VN_CAST(nodep, NodeProcedure); + if (procp && !v3Global.opt.profCFuncs()) { + nodep = procp->bodysp(); + pushDeletep(procp); } - // Move the logic to the function we're creating - nodep->unlinkFrBack(); - if (domainp == m_deleteDomainp) { - UINFO(4, " Ordering deleting pre-settled " << nodep << endl); - VL_DO_DANGLING(pushDeletep(nodep), nodep); - } else { - newFuncpr->addStmtsp(nodep); - if (v3Global.opt.outputSplitCFuncs()) { - // Add in the number of nodes we're adding - EmitCBaseCounterVisitor visitor(nodep); - newStmtsr += visitor.count(); + while (nodep) { + // Make or borrow a CFunc to contain the new statements + if (v3Global.opt.profCFuncs() + || (v3Global.opt.outputSplitCFuncs() + && v3Global.opt.outputSplitCFuncs() < newStmtsr)) { + // Put every statement into a unique function to ease profiling or reduce function + // size + newFuncpr = nullptr; } + if (!newFuncpr && domainp != m_deleteDomainp) { + const string name = cfuncName(modp, domainp, scopep, nodep); + newFuncpr = new AstCFunc(nodep->fileline(), name, scopep); + newFuncpr->argTypes(EmitCBaseVisitor::symClassVar()); + newFuncpr->symProlog(true); + newStmtsr = 0; + if (domainp->hasInitial() || domainp->hasSettle()) newFuncpr->slow(true); + scopep->addActivep(newFuncpr); + // Create top call to it + AstCCall* const callp = new AstCCall(nodep->fileline(), newFuncpr); + callp->argTypes("vlSymsp"); + // Where will we be adding the call? + AstActive* const newActivep = new AstActive(nodep->fileline(), name, domainp); + newActivep->addStmtsp(callp); + if (!activep) { + activep = newActivep; + } else { + activep->addNext(newActivep); + } + UINFO(6, " New " << newFuncpr << endl); + } + + AstNode* const nextp = nodep->nextp(); + // When processing statements in a procedure, unlink the current statement + if (nodep->backp()) nodep->unlinkFrBack(); + + if (domainp == m_deleteDomainp) { + UINFO(4, " Ordering deleting pre-settled " << nodep << endl); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } else { + newFuncpr->addStmtsp(nodep); + if (v3Global.opt.outputSplitCFuncs()) { + // Add in the number of nodes we're adding + EmitCBaseCounterVisitor visitor(nodep); + newStmtsr += visitor.count(); + } + } + + nodep = nextp; } } return activep; diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 8b7ba30d6..a681572c0 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -56,7 +56,7 @@ #include "V3Parse.h" #include "V3Width.h" #include "V3Unroll.h" -#include "V3Hashed.h" +#include "V3Hasher.h" #include #include @@ -314,7 +314,7 @@ class ParamProcessor final { key += "[" + cvtToStr(bdtp->left()) + ":" + cvtToStr(bdtp->right()) + "]"; } } - V3Hash hash = V3Hashed::uncachedHash(nodep); + V3Hash hash = V3Hasher::uncachedHash(nodep); // Force hash collisions -- for testing only if (VL_UNLIKELY(v3Global.opt.debugCollision())) hash = V3Hash(); int num; diff --git a/src/V3PreLex.h b/src/V3PreLex.h index b5b239a6a..3eeda4fa4 100644 --- a/src/V3PreLex.h +++ b/src/V3PreLex.h @@ -146,6 +146,10 @@ private: void lexStreamDepthAdd(int delta); }; +//====================================================================== +// Enum Class for `pragma protect encoding types +enum class Enctype : uint8_t { UUENCODE, BASE64, QUOTE_PRINTABLE, RAW, ERR }; + //====================================================================== // Class entry for each per-lexer state @@ -170,6 +174,9 @@ public: // Used only by V3PreLex.cpp and V3PreProc.cpp bool m_defQuote = false; // Definition value inside quote string m_defValue; // Definition value being built. int m_enterExit = 0; // For VL_LINE, the enter/exit level + int m_protLength = 0; // unencoded length for BASE64 + int m_protBytes = 0; // decoded length for BASE64 + Enctype m_encType; // encoding type for `pragma protect // CONSTRUCTORS V3PreLex(V3PreProcImp* preimpp, FileLine* filelinep) diff --git a/src/V3PreLex.l b/src/V3PreLex.l index 0ad5c5a61..81dcd763f 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -77,6 +77,11 @@ static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t, l) %x ARGMODE %x INCMODE %x PRTMODE +%x PRAGMA +%x PRAGMAERR +%x PRAGMAPRT +%x PRAGMAPRTERR +%x ENCBASE64 /* drop: Drop Ctrl-Z - can't pass thru or may EOF the output too soon */ @@ -112,12 +117,119 @@ bom [\357\273\277] "`undef" { FL_FWDC; return VP_UNDEF; } "`undefineall" { FL_FWDC; return VP_UNDEFINEALL; } "`error" { FL_FWDC; if (!pedantic()) return VP_ERROR; else return VP_DEFREF; } -"`pragma"{wsn}*[^\n\r]* { FL_FWDC; - const char* pointp = yytext + strlen("`pragma"); - while (isspace(*pointp)) ++pointp; - if (!*pointp && v3Global.opt.pedantic()) { - yyerrorf("`pragma is missing a pragma_expression."); + /* We wanted this to be next to `protect But it must be before `pramga */ + /* we win only because we both match to the end of the line so the length */ + /* is equal and we are first*/ +"encoding"{wsn}*[^\n\r]* { FL_FWDC; + int res; + char enctype[16]; // long enough to hold "quote-printable" + if (LEXP->m_protBytes > 0) { + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "multiple `pragma protected encoding sections"); } + res = sscanf(yytext + strlen("encoding"), " = (enctype = \"%15[A-Za-z0-9]\", line_length = %d, bytes = %d)", &enctype[0], &LEXP->m_protLength, &LEXP->m_protBytes); + if (res == 0) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "`pragma protected encoding must have an \"enctype\" field"); + LEXP->m_encType = !VL_STRCASECMP(enctype, "uuencode") ? Enctype::UUENCODE : + !VL_STRCASECMP(enctype, "base64") ? Enctype::BASE64 : + !VL_STRCASECMP(enctype, "quoted-printable") ? Enctype::QUOTE_PRINTABLE : + !VL_STRCASECMP(enctype, "raw") ? Enctype::RAW : Enctype::ERR; + if (LEXP->m_encType == Enctype::ERR) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "Illegal encoding type for `pragma protected encoding"); + if (LEXP->m_encType != Enctype::BASE64) + LEXP->curFilelinep()->v3warn(E_UNSUPPORTED, "Unsupported: only BASE64 is recognized for `pragma protected encoding"); + if (res == 3) { + if ((LEXP->m_encType == Enctype::BASE64) && (LEXP->m_protLength & 3)) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "line_length must be multiple of 4 for BASE64"); + } else { + // default values + LEXP->m_protBytes = 0; + LEXP->m_protLength = 76; // ?? default value not mentioned in IEEE spec + } + BEGIN(INITIAL); + return VP_TEXT; + } +"key_block"{wsn}*[\n\r] { + FL_FWDC; + linenoInc(); + BEGIN(ENCBASE64); + return VP_TEXT; } +"data_block"{wsn}*[\n\r] { + FL_FWDC; + linenoInc(); + LEXP->curFilelinep()->v3warn(PROTECTED, "A '`pragma protected data_block' encrypted section was detected and will be skipped."); + BEGIN(ENCBASE64); + return VP_TEXT; } +("begin_protected"|"end_protected")[\n\r] { FL_FWDC; linenoInc(); BEGIN(INITIAL); return VP_TEXT; } +"version="[^\n\r]*[\n\r] { + FL_FWDC; + linenoInc(); + BEGIN(INITIAL); + return VP_TEXT; } +("encrypt_agent"|"encrypt_agent_info"|"key_keyowner"|"key_keyname"){wsn}*={wsn}*[\"][^\n\r]*[\"][\n\r] { + FL_FWDC; + linenoInc(); + BEGIN(INITIAL); + return VP_TEXT; } +("data_method"|"key_method"){wsn}*={wsn}*[\"][^\n\r]*[\"][\n\r] { + FL_FWDC; + linenoInc(); + BEGIN(INITIAL); + return VP_TEXT; } + /* catch-all for unknown '`pragma protect' rules */ +. { yyless(0); + BEGIN(PRAGMAPRTERR); + return VP_TEXT; } +[A-Za-z0-9+/]+[=]{0,2}[\n\r] { FL_FWDC; linenoInc(); FL_BRK; + if ((yyourleng()-1) <= size_t(LEXP->m_protLength) && ((yyleng & 3) == 1)) { + LEXP->m_protBytes -= (yyleng-1)/4*3; + } else { + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "BASE64 line too long in `pragma protect key_bloock/data_block"); + } + if (yytext[yyleng-3] == '=') + LEXP->m_protBytes++; + if (yytext[yyleng-2] == '=') + LEXP->m_protBytes++; + if (LEXP->m_protBytes == 0) { + BEGIN(INITIAL); + } else if (LEXP->m_protBytes < 0) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "BASE64 encoding (too short) in `pragma protect key_bloock/data_block"); + /*return VP_TEXT;*/ } +{wsn}*[\n\r] { FL_FWDC; + if (LEXP->m_protBytes != 0) + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "BASE64 encoding length mismatch in `pragma protect key_bloock/data_block"); + linenoInc(); BEGIN(INITIAL); + return VP_TEXT; } + + /* Catch only empty `pragma lines */ +"`pragma"{wsn}*[\n\r] { + yyless(yyleng-1); FL_FWDC; + if (v3Global.opt.pedantic()) { + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "`pragma is missing a pragma_expression."); + } + return VP_TEXT; } + + /* catch all other nonempty `pragma */ +"`pragma"{wsn}*[^\n\r] { + yyless(yyleng-1); FL_FWDC; + if (!v3Global.opt.preprocOnly()) + BEGIN(PRAGMA); + return VP_TEXT; } +"protect"{wsn}* { FL_FWDC; BEGIN(PRAGMAPRT); return VP_TEXT;} + + /* catch-all for unknown `pragma rules */ +. { yyless(0); + BEGIN(PRAGMAERR); + return VP_TEXT; } + + /* the catch-all rule only got 1 char, lets get all line */ +[^\n\r]* { FL_FWDC; + /* Add a warning here for unknown pragmas if desired, at the moment , we don't */ + /* LEXP->curFilelinep()->v3warn(BADPRAGMA, "Unknown `pragma"); */ + BEGIN(INITIAL); + return VP_TEXT; } +[^\n\r]* { FL_FWDC; + LEXP->curFilelinep()->v3warn(BADSTDPRAGMA, "Unknown '`pragma protect' error"); + BEGIN(INITIAL); return VP_TEXT; } "`__FILE__" { FL_FWDC; static string rtnfile; diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 97bb3357f..82c2404ae 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -30,17 +30,21 @@ #include "V3Global.h" #include "V3Premit.h" #include "V3Ast.h" +#include "V3DupFinder.h" +#include "V3Stats.h" #include +constexpr int STATIC_CONST_MIN_WIDTH = 256; // Minimum size to extract to static constant + //###################################################################### // Structure for global state class PremitAssignVisitor final : public AstNVisitor { private: // NODE STATE - // AstVar::user4() // bool; occurs on LHS of current assignment - AstUser4InUse m_inuser4; + // AstVar::user3() // bool; occurs on LHS of current assignment + AstUser3InUse m_inuser3; // STATE bool m_noopt = false; // Disable optimization of variables in this block @@ -50,7 +54,7 @@ private: // VISITORS virtual void visit(AstNodeAssign* nodep) override { - // AstNode::user4ClearTree(); // Implied by AstUser4InUse + // AstNode::user3ClearTree(); // Implied by AstUser3InUse // LHS first as fewer varrefs iterateAndNextNull(nodep->lhsp()); // Now find vars marked as lhs @@ -59,9 +63,9 @@ private: virtual void visit(AstVarRef* nodep) override { // it's LHS var is used so need a deep temporary if (nodep->access().isWriteOrRW()) { - nodep->varp()->user4(true); + nodep->varp()->user3(true); } else { - if (nodep->varp()->user4()) { + if (nodep->varp()->user3()) { if (!m_noopt) UINFO(4, "Block has LHS+RHS var: " << nodep << endl); m_noopt = true; } @@ -88,9 +92,11 @@ private: // AstNodeMath::user() -> bool. True if iterated already // AstShiftL::user2() -> bool. True if converted to conditional // AstShiftR::user2() -> bool. True if converted to conditional + // AstConst::user2p() -> Replacement static variable pointer // *::user4() -> See PremitAssignVisitor AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; + // AstUser4InUse part of V3Hasher via V3DupFinder // STATE AstNodeModule* m_modp = nullptr; // Current module @@ -100,6 +106,11 @@ private: AstTraceInc* m_inTracep = nullptr; // Inside while loop, special statement additions bool m_assignLhs = false; // Inside assignment lhs, don't breakup extracts + V3DupFinder m_dupFinder; // Duplicate finder for static constants that can be reused + + VDouble0 m_staticConstantsExtracted; // Statistic tracking + VDouble0 m_staticConstantsReused; // Statistic tracking + // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -139,14 +150,6 @@ private: } } - AstVar* getBlockTemp(AstNode* nodep) { - string newvarname = (string("__Vtemp") + cvtToStr(m_modp->varNumGetInc())); - AstVar* varp - = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()); - m_cfuncp->addInitsp(varp); - return varp; - } - void insertBeforeStmt(AstNode* newp) { // Insert newp before m_stmtp if (m_inWhilep) { @@ -173,28 +176,65 @@ private: AstNRelinker linker; nodep->unlinkFrBack(&linker); - AstVar* varp = getBlockTemp(nodep); + AstVar* varp = nullptr; + + AstConst* const constp = VN_CAST(nodep, Const); + + const bool useStatic = constp && (constp->width() >= STATIC_CONST_MIN_WIDTH) + && !constp->num().isFourState(); + if (useStatic) { + // Extract as static constant + const auto& it = m_dupFinder.findDuplicate(constp); + if (it == m_dupFinder.end()) { + const string newvarname = string("__Vconst") + cvtToStr(m_modp->varNumGetInc()); + varp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, newvarname, + nodep->dtypep()); + varp->isConst(true); + varp->isStatic(true); + varp->valuep(constp); + m_modp->addStmtp(varp); + m_dupFinder.insert(constp); + nodep->user2p(varp); + ++m_staticConstantsExtracted; + } else { + varp = VN_CAST(it->second->user2p(), Var); + ++m_staticConstantsReused; + } + } else { + // Keep as local temporary + const string newvarname = string("__Vtemp") + cvtToStr(m_modp->varNumGetInc()); + varp + = new AstVar(nodep->fileline(), AstVarType::STMTTEMP, newvarname, nodep->dtypep()); + m_cfuncp->addInitsp(varp); + } + if (noSubst) varp->noSubst(true); // Do not remove varrefs to this in V3Const + // Replace node tree with reference to var AstVarRef* newp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); linker.relink(newp); - // Put assignment before the referencing statement - AstAssign* assp = new AstAssign( - nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep); - insertBeforeStmt(assp); - if (debug() > 8) assp->dumpTree(cout, "deepou:"); + + if (!useStatic) { + // Put assignment before the referencing statement + AstAssign* assp = new AstAssign( + nodep->fileline(), new AstVarRef(nodep->fileline(), varp, VAccess::WRITE), nodep); + insertBeforeStmt(assp); + if (debug() > 8) assp->dumpTree(cout, "deepou:"); + } + nodep->user1(true); // Don't add another assignment } // VISITORS virtual void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); - VL_RESTORER(m_modp); - { - m_modp = nodep; - m_cfuncp = nullptr; - iterateChildren(nodep); - } + UASSERT_OBJ(m_modp == nullptr, nodep, "Nested modules ?"); + UASSERT_OBJ(m_dupFinder.empty(), nodep, "Statements outside module ?"); + m_modp = nodep; + m_cfuncp = nullptr; + iterateChildren(nodep); + m_modp = nullptr; + m_dupFinder.clear(); } virtual void visit(AstCFunc* nodep) override { VL_RESTORER(m_cfuncp); @@ -401,7 +441,11 @@ private: public: // CONSTRUCTORS explicit PremitVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~PremitVisitor() override = default; + virtual ~PremitVisitor() { + V3Stats::addStat("Optimizations, Prelim static constants extracted", + m_staticConstantsExtracted); + V3Stats::addStat("Optimizations, Prelim static constants reused", m_staticConstantsReused); + } }; //---------------------------------------------------------------------- diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index ec267187c..e1bae6365 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -20,7 +20,7 @@ #include "V3Global.h" #include "V3String.h" #include "V3ProtectLib.h" -#include "V3Hashed.h" +#include "V3Hasher.h" #include "V3Task.h" #include @@ -87,9 +87,9 @@ private: iterateChildren(nodep); - V3Hash hash = V3Hashed::uncachedHash(m_cfilep); - m_hashValuep->addText(fl, cvtToStr(hash.fullValue()) + ";\n"); - m_cHashValuep->addText(fl, cvtToStr(hash.fullValue()) + "U;\n"); + V3Hash hash = V3Hasher::uncachedHash(m_cfilep); + m_hashValuep->addText(fl, cvtToStr(hash.value()) + ";\n"); + m_cHashValuep->addText(fl, cvtToStr(hash.value()) + "U;\n"); m_foundTop = true; } diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index d9b6aeabc..96e6a4dc8 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -18,12 +18,12 @@ // Each CFunc: // Look for a series of assignments that would look better in a loop: // -// ASSIGN(ARRAYREF(var, #), ARRAYREF(var, #)) -// ASSIGN(ARRAYREF(var, #+1), ARRAYREF(var, #+1)) +// ASSIGN(ARRAYREF(var, #), ARRAYREF(var, #+C)) +// ASSIGN(ARRAYREF(var, #+1), ARRAYREF(var, #+1+C)) // -> // Create __Vilp local variable // FOR(__Vilp = low; __Vilp <= high; ++__Vlip) -// ASSIGN(ARRAYREF(var, __Vilp), ARRAYREF(var, __Vilp)) +// ASSIGN(ARRAYREF(var, __Vilp), ARRAYREF(var, __Vilp + C)) // // Likewise vector assign to the same constant converted to a loop. // @@ -39,8 +39,6 @@ #include -constexpr unsigned RELOOP_MIN_ITERS = 40; // Need at least this many loops to do this optimization - //###################################################################### class ReloopVisitor final : public AstNVisitor { @@ -61,6 +59,7 @@ private: AstNodeSel* m_mgSelRp = nullptr; // Parent select, nullptr = constant AstNodeVarRef* m_mgVarrefLp = nullptr; // Parent varref AstNodeVarRef* m_mgVarrefRp = nullptr; // Parent varref, nullptr = constant + int64_t m_mgOffset = 0; // Index offset AstConst* m_mgConstRp = nullptr; // Parent RHS constant, nullptr = sel uint32_t m_mgIndexLo = 0; // Merge range uint32_t m_mgIndexHi = 0; // Merge range @@ -83,38 +82,50 @@ private: if (!m_mgAssignps.empty()) { uint32_t items = m_mgIndexHi - m_mgIndexLo + 1; UINFO(9, "End merge iter=" << items << " " << m_mgIndexHi << ":" << m_mgIndexLo << " " - << m_mgAssignps[0] << endl); - if (items >= RELOOP_MIN_ITERS) { + << m_mgOffset << " " << m_mgAssignps[0] << endl); + if (items >= static_cast(v3Global.opt.reloopLimit())) { UINFO(6, "Reloop merging items=" << items << " " << m_mgIndexHi << ":" - << m_mgIndexLo << " " << m_mgAssignps[0] << endl); + << m_mgIndexLo << " " << m_mgOffset << " " + << m_mgAssignps[0] << endl); ++m_statReloops; m_statReItems += items; // Transform first assign into for loop body - AstNodeAssign* bodyp = m_mgAssignps.front(); + AstNodeAssign* const bodyp = m_mgAssignps.front(); UASSERT_OBJ(bodyp->lhsp() == m_mgSelLp, bodyp, "Corrupt queue/state"); - FileLine* fl = bodyp->fileline(); - AstVar* itp = findCreateVarTemp(fl, m_mgCfuncp); + FileLine* const fl = bodyp->fileline(); + AstVar* const itp = findCreateVarTemp(fl, m_mgCfuncp); - AstNode* initp = new AstAssign(fl, new AstVarRef(fl, itp, VAccess::WRITE), - new AstConst(fl, m_mgIndexLo)); - AstNode* condp = new AstLte(fl, new AstVarRef(fl, itp, VAccess::READ), - new AstConst(fl, m_mgIndexHi)); - AstNode* incp = new AstAssign( + if (m_mgOffset > 0) { + UASSERT_OBJ(m_mgIndexLo >= m_mgOffset, bodyp, + "Reloop iteration starts at negative index"); + m_mgIndexLo -= m_mgOffset; + m_mgIndexHi -= m_mgOffset; + } + + AstNode* const initp = new AstAssign(fl, new AstVarRef(fl, itp, VAccess::WRITE), + new AstConst(fl, m_mgIndexLo)); + AstNode* const condp = new AstLte(fl, new AstVarRef(fl, itp, VAccess::READ), + new AstConst(fl, m_mgIndexHi)); + AstNode* const incp = new AstAssign( fl, new AstVarRef(fl, itp, VAccess::WRITE), new AstAdd(fl, new AstConst(fl, 1), new AstVarRef(fl, itp, VAccess::READ))); - AstWhile* whilep = new AstWhile(fl, condp, nullptr, incp); + AstWhile* const whilep = new AstWhile(fl, condp, nullptr, incp); initp->addNext(whilep); bodyp->replaceWith(initp); whilep->addBodysp(bodyp); // Replace constant index with new loop index - AstNode* lbitp = m_mgSelLp->bitp(); - lbitp->replaceWith(new AstVarRef(fl, itp, VAccess::READ)); + AstNode* const offsetp + = m_mgOffset == 0 ? nullptr : new AstConst(fl, std::abs(m_mgOffset)); + AstNode* const lbitp = m_mgSelLp->bitp(); + AstNode* const lvrefp = new AstVarRef(fl, itp, VAccess::READ); + lbitp->replaceWith(m_mgOffset > 0 ? new AstAdd(fl, lvrefp, offsetp) : lvrefp); VL_DO_DANGLING(lbitp->deleteTree(), lbitp); if (m_mgSelRp) { // else constant and no replace - AstNode* rbitp = m_mgSelRp->bitp(); - rbitp->replaceWith(new AstVarRef(fl, itp, VAccess::READ)); + AstNode* const rbitp = m_mgSelRp->bitp(); + AstNode* const rvrefp = new AstVarRef(fl, itp, VAccess::READ); + rbitp->replaceWith(m_mgOffset < 0 ? new AstAdd(fl, rvrefp, offsetp) : rvrefp); VL_DO_DANGLING(rbitp->deleteTree(), lbitp); } if (debug() >= 9) initp->dumpTree(cout, "-new: "); @@ -133,6 +144,7 @@ private: m_mgSelRp = nullptr; m_mgVarrefLp = nullptr; m_mgVarrefRp = nullptr; + m_mgOffset = 0; m_mgConstRp = nullptr; } } @@ -143,6 +155,7 @@ private: { m_cfuncp = nodep; iterateChildren(nodep); + mergeEnd(); // Finish last pending merge, if any } } virtual void visit(AstNodeAssign* nodep) override { @@ -155,7 +168,7 @@ private: return; } // Of a constant index - AstConst* lbitp = VN_CAST(lselp->bitp(), Const); + AstConst* const lbitp = VN_CAST(lselp->bitp(), Const); if (!lbitp) { mergeEnd(); return; @@ -164,53 +177,58 @@ private: mergeEnd(); return; } - uint32_t index = lbitp->toUInt(); + const uint32_t lindex = lbitp->toUInt(); // Of variable - AstNodeVarRef* lvarrefp = VN_CAST(lselp->fromp(), NodeVarRef); + AstNodeVarRef* const lvarrefp = VN_CAST(lselp->fromp(), NodeVarRef); if (!lvarrefp) { mergeEnd(); return; } // RHS is a constant or a select - AstConst* rconstp = VN_CAST(nodep->rhsp(), Const); - AstNodeSel* rselp = VN_CAST(nodep->rhsp(), NodeSel); + AstConst* const rconstp = VN_CAST(nodep->rhsp(), Const); + AstNodeSel* const rselp = VN_CAST(nodep->rhsp(), NodeSel); AstNodeVarRef* rvarrefp = nullptr; + uint32_t rindex = lindex; if (rconstp) { // Ok - } else { - if (!rselp) { - mergeEnd(); - return; - } - AstConst* rbitp = VN_CAST(rselp->bitp(), Const); + } else if (rselp) { + AstConst* const rbitp = VN_CAST(rselp->bitp(), Const); rvarrefp = VN_CAST(rselp->fromp(), NodeVarRef); - if (!rbitp || rbitp->toUInt() != index || !rvarrefp - || lvarrefp->varp() == rvarrefp->varp()) { + if (!rbitp || !rvarrefp || lvarrefp->varp() == rvarrefp->varp()) { mergeEnd(); return; } + rindex = rbitp->toUInt(); + } else { + mergeEnd(); + return; } if (m_mgSelLp) { // Old merge - if (m_mgCfuncp == m_cfuncp && m_mgNextp == nodep && m_mgSelLp->same(lselp) - && m_mgVarrefLp->same(lvarrefp) - && (m_mgConstRp - ? (rconstp && m_mgConstRp->same(rconstp)) - : (rselp && m_mgSelRp->same(rselp) && m_mgVarrefRp->same(rvarrefp))) - && (index == m_mgIndexLo - 1 || index == m_mgIndexHi + 1)) { + if (m_mgCfuncp == m_cfuncp // In same function + && m_mgNextp == nodep // Consecutive node + && m_mgVarrefLp->same(lvarrefp) // Same array on left hand side + && (m_mgConstRp // On the right hand side either ... + ? (rconstp && m_mgConstRp->same(rconstp)) // ... same constant + : (rselp && m_mgVarrefRp->same(rvarrefp))) // ... or same array + && (lindex == m_mgIndexLo - 1 || lindex == m_mgIndexHi + 1) // Left index +/- 1 + && (m_mgConstRp || lindex == rindex + m_mgOffset) // Same right index offset + ) { // Sequentially next to last assign; continue merge - if (index == m_mgIndexLo - 1) { - m_mgIndexLo = index; - } else if (index == m_mgIndexHi + 1) { - m_mgIndexHi = index; + if (lindex == m_mgIndexLo - 1) { + m_mgIndexLo = lindex; + } else if (lindex == m_mgIndexHi + 1) { + m_mgIndexHi = lindex; } - UINFO(9, "Continue merge i=" << index << " " << m_mgIndexHi << ":" << m_mgIndexLo + UINFO(9, "Continue merge i=" << lindex << " " << m_mgIndexHi << ":" << m_mgIndexLo << " " << nodep << endl); m_mgAssignps.push_back(nodep); m_mgNextp = nodep->nextp(); return; } else { - // This assign doesn't merge with previous assign, + UINFO(9, "End merge i=" + << lindex << " " << m_mgIndexHi << ":" << m_mgIndexLo << " " << nodep + << endl); // This assign doesn't merge with previous assign, // but should start a new merge mergeEnd(); } @@ -224,10 +242,11 @@ private: m_mgSelRp = rselp; m_mgVarrefLp = lvarrefp; m_mgVarrefRp = rvarrefp; + m_mgOffset = static_cast(lindex) - static_cast(rindex); m_mgConstRp = rconstp; - m_mgIndexLo = index; - m_mgIndexHi = index; - UINFO(9, "Start merge i=" << index << " " << nodep << endl); + m_mgIndexLo = lindex; + m_mgIndexHi = lindex; + UINFO(9, "Start merge i=" << lindex << " o=" << m_mgOffset << nodep << endl); } //-------------------- virtual void visit(AstVar*) override {} // Accelerate diff --git a/src/V3SenTree.h b/src/V3SenTree.h index 501157652..5abca02f6 100644 --- a/src/V3SenTree.h +++ b/src/V3SenTree.h @@ -23,7 +23,7 @@ #include "verilatedos.h" #include "V3Ast.h" -#include "V3Hashed.h" +#include "V3Hasher.h" #include @@ -37,7 +37,7 @@ private: // TYPES struct HashSenTree { size_t operator()(const AstSenTree* kp) const { - return V3Hashed::uncachedHash(kp).fullValue(); + return V3Hasher::uncachedHash(kp).value(); } }; diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 02e6692cc..b992f9292 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -979,6 +979,17 @@ private: } SimStackNode stackNode(nodep, &tconnects); m_callStack.push_front(&stackNode); + // Clear output variable + if (auto* const basicp = VN_CAST(funcp->fvarp(), Var)->basicp()) { + AstConst cnst(funcp->fvarp()->fileline(), AstConst::WidthedValue(), basicp->widthMin(), + 0); + if (basicp->isZeroInit()) { + cnst.num().setAllBits0(); + } else { + cnst.num().setAllBitsX(); + } + newValue(funcp->fvarp(), &cnst); + } // Evaluate the function iterate(funcp); m_callStack.pop_front(); diff --git a/src/V3Table.cpp b/src/V3Table.cpp index c31adb692..eb29e3639 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -342,7 +342,7 @@ private: AstVarScope* findDuplicateTable(AstVarScope* vsc1p) { // See if another table we've created is identical, if so use it for both. - // (A more 'modern' way would be to instead use V3Hashed::findDuplicate) + // (A more 'modern' way would be to instead use V3DupFinder::findDuplicate) AstVar* var1p = vsc1p->varp(); for (AstVarScope* vsc2p : m_modTableVscs) { AstVar* var2p = vsc2p->varp(); diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 66cbd18b3..9dcfc0c04 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1157,7 +1157,8 @@ private: cfuncp->argTypes(EmitCBaseVisitor::symClassVar()); if (cfuncp->name() == "new") { cfuncp->addInitsp( - new AstCStmt(nodep->fileline(), "_ctor_var_reset(vlSymsp);\n")); + new AstCStmt(nodep->fileline(), + VIdProtect::protect("_ctor_var_reset") + "(vlSymsp);\n")); } } } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 49ee14933..601c285e0 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -42,7 +42,7 @@ #include "V3Trace.h" #include "V3EmitCBase.h" #include "V3Graph.h" -#include "V3Hashed.h" +#include "V3DupFinder.h" #include "V3Stats.h" #include @@ -154,8 +154,8 @@ public: class TraceVisitor final : public EmitCBaseVisitor { private: // NODE STATE - // V3Hashed - // Ast*::user4() // V3Hashed calculation + // V3Hasher in V3DupFinder + // Ast*::user4() // V3Hasher calculation // Cleared entire netlist // AstCFunc::user1() // V3GraphVertex* for this node // AstTraceDecl::user1() // V3GraphVertex* for this node @@ -165,7 +165,7 @@ private: AstUser1InUse m_inuser1; AstUser2InUse m_inuser2; AstUser3InUse m_inuser3; - // AstUser4InUse In V3Hashed + // AstUser4InUse In V3Hasher via V3DupFinder // STATE AstNodeModule* m_topModp = nullptr; // Module to add variables to @@ -194,7 +194,7 @@ private: void detectDuplicates() { UINFO(9, "Finding duplicates\n"); // Note uses user4 - V3Hashed hashed; // Duplicate code detection + V3DupFinder dupFinder; // Duplicate code detection // Hash all of the values the traceIncs need for (const V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { @@ -205,13 +205,9 @@ private: UASSERT_OBJ(nodep->valuep()->backp() == nodep, nodep, "Trace duplicate back needs consistency," " so we can map duplicates back to TRACEINCs"); - hashed.hash(nodep->valuep()); - UINFO(8, " Hashed " << std::hex << hashed.nodeHash(nodep->valuep()) << " " - << nodep << endl); - // Just keep one node in the map and point all duplicates to this node - if (hashed.findDuplicate(nodep->valuep()) == hashed.end()) { - hashed.hashAndInsert(nodep->valuep()); + if (dupFinder.findDuplicate(nodep->valuep()) == dupFinder.end()) { + dupFinder.insert(nodep->valuep()); } } } @@ -221,10 +217,10 @@ private: if (TraceTraceVertex* const vvertexp = dynamic_cast(itp)) { AstTraceDecl* const nodep = vvertexp->nodep(); if (nodep->valuep() && !vvertexp->duplicatep()) { - const auto dupit = hashed.findDuplicate(nodep->valuep()); - if (dupit != hashed.end()) { + const auto dupit = dupFinder.findDuplicate(nodep->valuep()); + if (dupit != dupFinder.end()) { const AstTraceDecl* const dupDeclp - = VN_CAST_CONST(hashed.iteratorNodep(dupit)->backp(), TraceDecl); + = VN_CAST_CONST(dupit->second->backp(), TraceDecl); UASSERT_OBJ(dupDeclp, nodep, "Trace duplicate of wrong type"); TraceTraceVertex* const dupvertexp = dynamic_cast(dupDeclp->user1u().toGraphVertex()); @@ -237,7 +233,6 @@ private: } } } - hashed.clear(); } void graphSimplify(bool initial) { diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 5878a70c9..e79db26eb 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -127,6 +127,7 @@ private: new AstAssign(fl, prep, new AstVarRef(fl, varp, VAccess::READ)))), nullptr); newp->branchPred(VBranchPred::BP_LIKELY); + newp->isBoundsCheck(true); if (debug() >= 9) newp->dumpTree(cout, " _new: "); abovep->addNextStmt(newp, abovep); prep->user2p(newp); // Save so we may LogAnd it next time diff --git a/src/V3Width.cpp b/src/V3Width.cpp index a36501eb1..08204e1d0 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -492,7 +492,7 @@ private: // signed: Unsigned (11.8.1) // width: LHS + RHS AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); - userIterateAndNext(vdtypep, WidthVP(SELF, BOTH).p()); + userIterate(vdtypep, WidthVP(SELF, BOTH).p()); if (VN_IS(vdtypep, QueueDType)) { // Queue "element 0" is lhsp, so we need to swap arguments auto* newp = new AstConsQueue(nodep->fileline(), nodep->rhsp()->unlinkFrBack(), @@ -2457,7 +2457,7 @@ private: AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); AstBasicDType* basicp = fromDtp ? fromDtp->basicp() : nullptr; UINFO(9, " from dt " << fromDtp << endl); - userIterateAndNext(fromDtp, WidthVP(SELF, BOTH).p()); + userIterate(fromDtp, WidthVP(SELF, BOTH).p()); if (AstEnumDType* adtypep = VN_CAST(fromDtp, EnumDType)) { methodCallEnum(nodep, adtypep); } else if (AstAssocArrayDType* adtypep = VN_CAST(fromDtp, AssocArrayDType)) { @@ -3310,7 +3310,9 @@ private: while (const AstConstDType* vdtypep = VN_CAST(dtypep, ConstDType)) { dtypep = vdtypep->subDTypep()->skipRefp(); } - userIterateAndNext(dtypep, WidthVP(SELF, BOTH).p()); + + userIterate(dtypep, WidthVP(SELF, BOTH).p()); + if (auto* vdtypep = VN_CAST(dtypep, NodeUOrStructDType)) { VL_DO_DANGLING(patternUOrStruct(nodep, vdtypep, defaultp), nodep); } else if (auto* vdtypep = VN_CAST(dtypep, NodeArrayDType)) { @@ -3864,27 +3866,6 @@ private: if (nodep->timeunit().isNone()) { nodep->v3fatalSrc("display %t has no time units"); } - double scale = nodep->timeunit().multiplier() - / v3Global.rootp()->timeprecision().multiplier(); - if (scale != 1.0) { - AstNode* newp; - AstNRelinker relinkHandle; - argp->unlinkFrBack(&relinkHandle); - if (argp->isDouble()) { // Convert it - ch = '^'; - newp = new AstMulD( - argp->fileline(), - new AstConst(argp->fileline(), AstConst::RealDouble(), scale), - argp); - } else { - newp = new AstMul(argp->fileline(), - new AstConst(argp->fileline(), - AstConst::Unsized64(), - std::llround(scale)), - argp); - } - relinkHandle.relink(newp); - } argp = nextp; } break; @@ -6125,6 +6106,7 @@ private: } void userIterateAndNext(AstNode* nodep, WidthVP* vup) { if (!nodep) return; + if (nodep->didWidth()) return; // Avoid iterating list we have already iterated { VL_RESTORER(m_vup); m_vup = vup; diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp index 68e22cc70..970aab9c3 100644 --- a/src/VlcMain.cpp +++ b/src/VlcMain.cpp @@ -27,6 +27,8 @@ #define V3ERROR_NO_GLOBAL_ #include "V3Error.cpp" #include "V3String.cpp" +#define V3OPTION_PARSER_NO_VOPTION_BOOL +#include "V3OptionParser.cpp" #include "V3Os.cpp" #include "VlcTop.cpp" @@ -47,74 +49,43 @@ string VlcOptions::version() { return ver; } -bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) { - // if sw==arg, then return true (found it), and flag=true - // if sw=="-no-arg", then return true (found it), and flag=false - // if sw=="-noarg", then return true (found it), and flag=false - // else return false - if (arg[0] != '-') v3fatalSrc("OnOff switches must have leading dash."); - if (0 == strcmp(sw, arg)) { - flag = true; - return true; - } else if (0 == strncmp(sw, "-no", 3) && (0 == strcmp(sw + 3, arg + 1))) { - flag = false; - return true; - } else if (0 == strncmp(sw, "-no-", 4) && (0 == strcmp(sw + 4, arg + 1))) { - flag = false; - return true; - } - return false; -} - void VlcOptions::parseOptsList(int argc, char** argv) { + V3OptionParser parser; + 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("-debug", CbCall, []() { V3Error::debugDefault(3); }); + DECL_OPTION("-debugi", CbVal, [](int v) { V3Error::debugDefault(v); }); + DECL_OPTION("-V", CbCall, []() { + showVersion(true); + std::exit(0); + }); + DECL_OPTION("-version", CbCall, []() { + showVersion(false); + std::exit(0); + }); + DECL_OPTION("-write", Set, &m_writeFile); + DECL_OPTION("-write-info", Set, &m_writeInfoFile); + parser.finalize(); + // Parse parameters // Note argc and argv DO NOT INCLUDE the filename in [0]!!! // May be called recursively when there are -f files. for (int i = 0; i < argc;) { UINFO(9, " Option: " << argv[i] << endl); if (argv[i][0] == '-') { - const char* sw = argv[i]; - bool flag = true; - // Allow gnu -- switches - if (sw[0] == '-' && sw[1] == '-') ++sw; - // Single switches - if (onoff(sw, "-annotate-all", flag /*ref*/)) { - m_annotateAll = flag; - } else if (onoff(sw, "-rank", flag /*ref*/)) { - m_rank = flag; - } else if (onoff(sw, "-unlink", flag /*ref*/)) { - m_unlink = flag; - } - // Parameterized switches - else if (!strcmp(sw, "-annotate-min") && (i + 1) < argc) { - ++i; - m_annotateMin = atoi(argv[i]); - } else if (!strcmp(sw, "-annotate") && (i + 1) < argc) { - ++i; - m_annotateOut = argv[i]; - } else if (!strcmp(sw, "-debug")) { - V3Error::debugDefault(3); - } else if (!strcmp(sw, "-debugi") && (i + 1) < argc) { - ++i; - V3Error::debugDefault(atoi(argv[i])); - } else if (!strcmp(sw, "-V")) { - showVersion(true); - std::exit(0); - } else if (!strcmp(sw, "-version")) { - showVersion(false); - std::exit(0); - } else if (!strcmp(sw, "-write") && (i + 1) < argc) { - ++i; - m_writeFile = argv[i]; - } else if (!strcmp(sw, "-write-info") && (i + 1) < argc) { - ++i; - m_writeInfoFile = argv[i]; + if (int consumed = parser.parse(i, argc, argv)) { + i += consumed; } else { - v3fatal("Invalid option: " << argv[i]); + v3fatal("Invalid option: " << argv[i] << parser.getSuggestion(argv[i])); + ++i; } - ++i; - } // - options - else { + } else { addReadFile(argv[i]); ++i; } diff --git a/src/VlcOptions.h b/src/VlcOptions.h index fc76f4b76..22d98dd4a 100644 --- a/src/VlcOptions.h +++ b/src/VlcOptions.h @@ -47,7 +47,6 @@ class VlcOptions final { private: // METHODS static void showVersion(bool verbose); - static bool onoff(const char* sw, const char* arg, bool& flag); public: // CONSTRUCTORS diff --git a/src/astgen b/src/astgen index a5057b7a8..a2cf43088 100755 --- a/src/astgen +++ b/src/astgen @@ -621,7 +621,7 @@ def write_types(filename): fh.write(" }\n") -def write_header(filename): +def write_macros(filename): with open_file(filename) as fh: typen = "None" base = "None" @@ -629,10 +629,7 @@ def write_header(filename): in_filename = "V3AstNodes.h" ifile = Args.I + "/" + in_filename with open(ifile) as ifh: - - fh.write("#line 1 \"../" + in_filename + "\"\n") - - for line in ifh: + for (lineno, line) in enumerate(ifh, 1): # Drop expanded macro definitions - but keep empty line so compiler # message locations are accurate line = re.sub(r'^\s*#(define|undef)\s+ASTGEN_.*$', '', line) @@ -644,13 +641,20 @@ def write_header(filename): if match: typen = match.group(1) base = match.group(4) + if not typen.startswith("Node"): + macro = "#define ASTGEN_SUPER_{t}(...) {b}(AstType::at{t}, __VA_ARGS__)\n" \ + .format(b=base, t=typen) + fh.write(macro) - # Substitute macros - line = re.sub(r'\bASTGEN_SUPER\s*\(', - base + "(AstType::at" + typen + ", ", line) - - # Emit the line - fh.write(line) + match = re.search(r"ASTGEN_SUPER_(\w+)", line) + if match: + if typen != match.group(1): + print(( + "V3AstNodes.h:{l} ERROR: class Ast{t} calls wrong superclass " + + + "constructor macro (should call ASTGEN_SUPER_{t})" + ).format(l=lineno, t=typen)) + sys.exit(1) ###################################################################### @@ -708,7 +712,7 @@ if Args.classes: write_visitor("V3Ast__gen_visitor.h") write_impl("V3Ast__gen_impl.h") write_types("V3Ast__gen_types.h") - write_header("V3AstNodes__gen.h") + write_macros("V3AstNodes__gen_macros.h") for cpt in Args.infiles: if not re.search(r'.cpp$', cpt): diff --git a/test_regress/CMakeLists.txt b/test_regress/CMakeLists.txt index 28a045961..413578a64 100644 --- a/test_regress/CMakeLists.txt +++ b/test_regress/CMakeLists.txt @@ -52,9 +52,10 @@ string(REGEX REPLACE "(^|;)--" "\\1-" getarg(TEST_VERILATOR_ARGS_NORM "-prefix" TEST_PREFIX) getarg(TEST_VERILATOR_ARGS_NORM "-threads" TEST_THREADS) +getarg(TEST_VERILATOR_ARGS_NORM "-trace-threads" TEST_TRACE_THREADS) # Strip unwanted args with 1 parameter -string(REGEX REPLACE "(^|;)--?(Mdir|make|prefix|threads);[^;]*" "" +string(REGEX REPLACE "(^|;)--?(Mdir|make|prefix|threads|trace-threads);[^;]*" "" TEST_VERILATOR_ARGS "${TEST_VERILATOR_ARGS}") # Strip unwanted args @@ -81,6 +82,9 @@ endif() if(TEST_THREADS) list(APPEND verilate_ARGS THREADS ${TEST_THREADS}) endif() +if(TEST_TRACE_THREADS) + list(APPEND verilate_ARGS TRACE_THREADS ${TEST_TRACE_THREADS}) +endif() if(TEST_SYSTEMC) list(APPEND verilate_ARGS SYSTEMC) endif() diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 4bd0ccc70..54dd82683 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -908,7 +908,7 @@ sub compile_vlt_flags { unshift @verilator_flags, "--trace-threads 2" if $param{vltmt} && $checkflags =~ /-trace-fst /; unshift @verilator_flags, "--debug-partition" if $param{vltmt}; unshift @verilator_flags, "-CFLAGS -ggdb -LDFLAGS -ggdb" if $opt_gdbsim; - unshift @verilator_flags, "-CFLAGS -fsanitize=address -LDFLAGS -fsanitize=address" if $param{sanitize}; + unshift @verilator_flags, "-CFLAGS -fsanitize=address,undefined -LDFLAGS -fsanitize=address,undefined" if $param{sanitize}; unshift @verilator_flags, "--make gmake" if $param{verilator_make_gmake}; unshift @verilator_flags, "--make cmake" if $param{verilator_make_cmake}; unshift @verilator_flags, "--exe" if @@ -2304,6 +2304,10 @@ sub cfg_with_threaded { return 1; # C++11 now always required } +sub cfg_with_ccache { + return `grep "OBJCACHE \?= ccache" "$ENV{VERILATOR_ROOT}/include/verilated.mk"` ne ""; +} + sub tries { # Number of retries when reading logfiles, generally only need many # retries when system is busy running a lot of tests @@ -2449,10 +2453,12 @@ sub _lineno_match { my $lineno = shift; my $lines = shift; return 1 if !defined $lines; - if ($lines =~ /^(\d+)$/) { - return $1 == $lineno; - } elsif ($lines =~ /^(\d+)-(\d+)$/) { - return $1 <= $lineno && $2 >= $lineno; + foreach my $lc (split /,/, $lines) { + if ($lc =~ /^(\d+)$/) { + return 1 if $1 == $lineno; + } elsif ($lc =~ /^(\d+)-(\d+)$/) { + return 1 if $1 <= $lineno && $2 >= $lineno; + } } return 0; } diff --git a/test_regress/t/TestCheck.h b/test_regress/t/TestCheck.h index 947afaed9..17236efbf 100644 --- a/test_regress/t/TestCheck.h +++ b/test_regress/t/TestCheck.h @@ -54,6 +54,15 @@ static const bool verbose = false; } \ } while (0) +#define TEST_CHECK_Z(got) \ + do { \ + if ((got)) { \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << std::hex \ + << ": GOT!= NULL EXP=NULL" << std::endl; \ + ++errors; \ + } \ + } while (0) + #define TEST_CHECK_NZ(got) \ do { \ if (!(got)) { \ diff --git a/test_regress/t/t_assoc2.pl b/test_regress/t/t_assoc2.pl new file mode 100755 index 000000000..9a15dd2cc --- /dev/null +++ b/test_regress/t/t_assoc2.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_assoc2.v b/test_regress/t/t_assoc2.v new file mode 100644 index 000000000..4c938a35a --- /dev/null +++ b/test_regress/t/t_assoc2.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, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`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 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 checkg(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='%g' exp='%g'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0); + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc=0; + + // associative array of an associative array + logic [31:0] a [logic [31:0]][logic [63:0]]; + + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 1) begin + a[5][8] = 8; + a[5][9] = 9; + end + else if (cyc == 2) begin + `checkh(a[5][8], 8); + `checkh(a[5][9], 9); + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_ccache_report.pl b/test_regress/t/t_ccache_report.pl new file mode 100755 index 000000000..d874fd27c --- /dev/null +++ b/test_regress/t/t_ccache_report.pl @@ -0,0 +1,48 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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->cfg_with_ccache) { + skip("Requires configuring with ccache"); +} + +top_filename("t_a1_first_cc.v"); + +# This test requires rebuilding the object files to check the ccache log +foreach my $filename (glob ("$Self->{obj_dir}/*.o")) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +compile( + verilator_flags2 => ['--trace'], + make_flags => "ccache-report" + ); + +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 +run(cmd => ["sed", "-i", "-e", "'s/ : .*/ : IGNORED/; /|/s/.*/IGNORED/;'", $report]); +files_identical($report, "t/$Self->{name}__ccache_report_initial.out"); + +# Now rebuild again (should be all up to date) +run( + logfile => "$Self->{obj_dir}/rebuild.log", + cmd => ["make", "-C", $Self->{obj_dir}, + "-f", "$Self->{VM_PREFIX}.mk", + $Self->{VM_PREFIX}, "ccache-report"] + ); + +files_identical($report, "t/$Self->{name}__ccache_report_rebuild.out"); + +ok(1); +1; diff --git a/test_regress/t/t_ccache_report__ccache_report_initial.out b/test_regress/t/t_ccache_report__ccache_report_initial.out new file mode 100644 index 000000000..2a6c77138 --- /dev/null +++ b/test_regress/t/t_ccache_report__ccache_report_initial.out @@ -0,0 +1,12 @@ +################################################################################ +ccache report (from verilator_ccache_report) : + +Compiled object files: +Vt_ccache_report__ALL.o : IGNORED + +Summary: +IGNORED + +Longest: +IGNORED +################################################################################ diff --git a/test_regress/t/t_ccache_report__ccache_report_rebuild.out b/test_regress/t/t_ccache_report__ccache_report_rebuild.out new file mode 100644 index 000000000..767cd181a --- /dev/null +++ b/test_regress/t/t_ccache_report__ccache_report_rebuild.out @@ -0,0 +1,5 @@ +################################################################################ +ccache report (from verilator_ccache_report) : + +All object files up to date +################################################################################ diff --git a/test_regress/t/t_class_extends_protect_ids.pl b/test_regress/t/t_class_extends_protect_ids.pl new file mode 100755 index 000000000..b48534f3c --- /dev/null +++ b/test_regress/t/t_class_extends_protect_ids.pl @@ -0,0 +1,34 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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_all => 1); + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +top_filename("t/t_class_extends.v"); + +compile( + make_flags => 'VM_PARALLEL_BUILDS=1', # bug2775 + verilator_flags2 => ["--protect-ids", + "--protect-key SECRET_KEY"] + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_local_protect_ids.pl b/test_regress/t/t_class_local_protect_ids.pl new file mode 100755 index 000000000..a1bab0242 --- /dev/null +++ b/test_regress/t/t_class_local_protect_ids.pl @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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_all => 1); + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +top_filename("t/t_class_local.v"); + +compile( + verilator_flags2 => ["--protect-ids", + "--protect-key SECRET_KEY"] + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_static_method_protect_ids.pl b/test_regress/t/t_class_static_method_protect_ids.pl new file mode 100755 index 000000000..876725638 --- /dev/null +++ b/test_regress/t/t_class_static_method_protect_ids.pl @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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_all => 1); + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +top_filename("t/t_class_static_method.v"); + +compile( + verilator_flags2 => ["--protect-ids", + "--protect-key SECRET_KEY"] + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_virtual_protect_ids.pl b/test_regress/t/t_class_virtual_protect_ids.pl new file mode 100755 index 000000000..ff478e073 --- /dev/null +++ b/test_regress/t/t_class_virtual_protect_ids.pl @@ -0,0 +1,33 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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_all => 1); + +# This test makes randomly named .cpp/.h files, which tend to collect, so remove them first +foreach my $filename (glob ("$Self->{obj_dir}/*_PS*.cpp" + ." $Self->{obj_dir}/*_PS*.h" + ." $Self->{obj_dir}/*.d" )) { + print "rm $filename\n" if $Self->{verbose}; + unlink $filename; +} + +top_filename("t/t_class_virtual.v"); + +compile( + verilator_flags2 => ["--protect-ids", + "--protect-key SECRET_KEY"] + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index b9881d967..e8f31dfe1 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -57,7 +57,7 @@ module t(/*AUTOARG*/ $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'hfab547b426149442 +`define EXPECTED_SUM 64'he78be35df15ae0ab if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; @@ -80,7 +80,7 @@ module Test(/*AUTOARG*/ output logic o; - logic [3:0] tmp; + logic [4:0] tmp; assign o = ^tmp; always_ff @(posedge clk) begin @@ -100,6 +100,7 @@ module Test(/*AUTOARG*/ tmp[1] <= ((32'd2 ** i) & 32'h10) == 32'b0; // replacePowShift tmp[2] <= ((d0 & d1) | (d0 & d2))^ ((d3 & d4) | (d5 & d4)); // replaceAndOr() tmp[3] <= d0 <-> d1; // replaceLogEq() + tmp[4] <= i[0] & (i[1] & (i[2] & (i[3] | d[4]))); // ConstBitOpTreeVisitor::m_frozenNodes end endmodule diff --git a/test_regress/t/t_const_opt_cov.pl b/test_regress/t/t_const_opt_cov.pl index 1e0a96b74..0a72e4f4f 100755 --- a/test_regress/t/t_const_opt_cov.pl +++ b/test_regress/t/t_const_opt_cov.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2=>["-Wno-UNOPTTHREADS", "--stats", "--coverage"], + verilator_flags2=>["-Wno-UNOPTTHREADS", "--stats", "--coverage", "--trace"], ); execute( diff --git a/test_regress/t/t_const_opt_cov.v b/test_regress/t/t_const_opt_cov.v index 245309007..c939ad806 100644 --- a/test_regress/t/t_const_opt_cov.v +++ b/test_regress/t/t_const_opt_cov.v @@ -20,19 +20,20 @@ module t(/*AUTOARG*/ logic bank_rd_vec_m3; always_ff @(posedge clk) bank_rd_vec_m3 <= crc[33]; - - wire out; - ecc_check_pipe u_bank_data_ecc_check( - .clk (clk), - .bank_rd_m3 (bank_rd_vec_m3), - .data_i (in), - .ecc_err_o (out) - ); - - + logic [3:0][31:0] data_i; + wire [3:0] out; + for (genvar i = 0; i < 4; ++i) begin + always_ff @(posedge clk) data_i[i] <= crc[63:32]; + ecc_check_pipe u_bank_data_ecc_check( + .clk (clk), + .bank_rd_m3 (bank_rd_vec_m3), + .data_i ({1'b0, data_i[i]}), + .ecc_err_o (out[i]) + ); + end // Aggregate outputs into a single result vector - wire [63:0] result = {63'b0, out}; + wire [63:0] result = {60'b0, out}; // Test loop always @ (posedge clk) begin @@ -54,7 +55,7 @@ module t(/*AUTOARG*/ $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'h768b162c5835e35b +`define EXPECTED_SUM 64'ha2601675a6ae4972 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_const_opt_red.pl b/test_regress/t/t_const_opt_red.pl index 573f3e618..4cc2b40a0 100755 --- a/test_regress/t/t_const_opt_red.pl +++ b/test_regress/t/t_const_opt_red.pl @@ -19,7 +19,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 135); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 141); } ok(1); diff --git a/test_regress/t/t_const_opt_red.v b/test_regress/t/t_const_opt_red.v index ee5d9fd06..1f5e407d7 100644 --- a/test_regress/t/t_const_opt_red.v +++ b/test_regress/t/t_const_opt_red.v @@ -162,7 +162,7 @@ module t(/*AUTOARG*/ $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'he9b854d521ebb8b6 +`define EXPECTED_SUM 64'h727fb78d09c1981e if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); $finish; @@ -190,7 +190,9 @@ module Test(/*AUTOARG*/ output logic z1, z2, z3, z4, z5, z6, z7; logic [127:0] d; + logic [17:0] e; always_ff @(posedge clk) d <= {i, ~i, ~i, i}; + always_ff @(posedge clk) e <= i[17:00]; always_ff @(posedge clk) begin a1 <= (i[5] & ~i[3] & i[1]); @@ -203,7 +205,7 @@ module Test(/*AUTOARG*/ a8 <= &(~i[5:3]); a9 <= ~i[5] & !i[4] & !i[3] && ~i[5] && !i[4]; a10 <= ~(i[5] & ~d[3]) & (!i[5] & d[1]); // cannot be optimized - a11 <= d[0] & d[33] & d[66] & d[99] & !d[31] & !d[62] & !d[93] & !d[124]; + a11 <= d[0] & d[33] & d[66] & d[99] & !d[31] & !d[62] & !d[93] & !d[124] & e[0] & !e[1] & e[2]; // o1 <= (~i[5] | i[3] | ~i[1]); o2 <= (i[5]!=1 | i[3]!=0 | i[1]!=1); @@ -215,7 +217,7 @@ module Test(/*AUTOARG*/ o8 <= |(~i[5:3]); o9 <= ~i[5] | !i[4] | ~i[3] || !i[5] || ~i[4]; o10 <= ~(~i[5] | d[3]) | (i[5] | ~d[1]); // cannot be optimized - o11 <= d[0] | d[33] | d[66] | d[99] | !d[31] | !d[62] | !d[93] | !d[124]; + o11 <= d[0] | d[33] | d[66] | d[99] | !d[31] | !d[62] | !d[93] | !d[124] | e[0] | !e[1] | e[2]; // x1 <= (i[5] ^ ~i[3] ^ i[1]); x2 <= (i[5]==1 ^ i[3]==0 ^ i[1]==1); @@ -225,7 +227,7 @@ module Test(/*AUTOARG*/ x6 <= i[5] ^ ~i[3] ^ i[1] ^ i[3] ^ !i[1] ^ i[3] ^ ~i[1]; x7 <= i[5] ^ (^((i & 32'b001010) ^ 32'b001000)); x8 <= ~(~i[5] ^ d[3]) ^ (i[5] ^ ~d[1]); - x9 <= d[0] ^ d[33] ^ d[66] ^ d[99] ^ !d[31] ^ !d[62] ^ !d[93] ^ !d[124]; + x9 <= d[0] ^ d[33] ^ d[66] ^ d[99] ^ !d[31] ^ !d[62] ^ !d[93] ^ !d[124] ^ e[0] ^ !e[1] ^ e[2]; // // All zero/all one cases z1 <= (i[5] & ~i[3] & ~i[5]); diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index e37daa2fd..aeee81350 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -45,7 +45,7 @@ module Vt_debug_emitv; $display("stmt"); $display("stmt"); end - + ???? // CFUNC '_final_TOP' $_CSTMT(Vt_debug_emitv* const __restrict vlTOPp VL_ATTR_UNUSED = vlSymsp->TOPp; ); diff --git a/test_regress/t/t_dpi_arg_inout_type__Dpi.out b/test_regress/t/t_dpi_arg_inout_type__Dpi.out index 3f0f7e242..01379ddcd 100644 --- a/test_regress/t/t_dpi_arg_inout_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_inout_type__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_array_2_state_1(svBitVecVal* x); extern void e_array_2_state_128(svBitVecVal* x); @@ -79,7 +79,7 @@ extern "C" { extern void e_union_4_state_33(svLogicVecVal* x); extern void e_union_4_state_64(svLogicVecVal* x); extern void e_union_4_state_65(svLogicVecVal* x); - + // DPI IMPORTS extern void check_exports(); extern void i_array_2_state_1(svBitVecVal* x); @@ -148,7 +148,7 @@ extern "C" { extern void i_union_4_state_33(svLogicVecVal* x); extern void i_union_4_state_64(svLogicVecVal* x); extern void i_union_4_state_65(svLogicVecVal* x); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out b/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out index 918872073..e4f0d5949 100644 --- a/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_bit121_0d(svBitVecVal* val); extern void e_bit121_1d(svBitVecVal* val); @@ -93,7 +93,7 @@ extern "C" { extern void e_time_1d(svLogicVecVal* val); extern void e_time_2d(svLogicVecVal* val); extern void e_time_3d(svLogicVecVal* val); - + // DPI IMPORTS extern void check_exports(); extern void* get_non_null(); @@ -177,7 +177,7 @@ extern "C" { extern void i_time_1d(svLogicVecVal* val); extern void i_time_2d(svLogicVecVal* val); extern void i_time_3d(svLogicVecVal* val); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_input_type__Dpi.out b/test_regress/t/t_dpi_arg_input_type__Dpi.out index ea56ffe00..632b44b9c 100644 --- a/test_regress/t/t_dpi_arg_input_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_input_type__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_array_2_state_1(const svBitVecVal* i); extern void e_array_2_state_128(const svBitVecVal* i); @@ -79,7 +79,7 @@ extern "C" { extern void e_union_4_state_33(const svLogicVecVal* i); extern void e_union_4_state_64(const svLogicVecVal* i); extern void e_union_4_state_65(const svLogicVecVal* i); - + // DPI IMPORTS extern void check_exports(); extern void i_array_2_state_1(const svBitVecVal* i); @@ -148,7 +148,7 @@ extern "C" { extern void i_union_4_state_33(const svLogicVecVal* i); extern void i_union_4_state_64(const svLogicVecVal* i); extern void i_union_4_state_65(const svLogicVecVal* i); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_input_unpack__Dpi.out b/test_regress/t/t_dpi_arg_input_unpack__Dpi.out index f6eee80e8..0867d13f0 100644 --- a/test_regress/t/t_dpi_arg_input_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_input_unpack__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_bit121_0d(const svBitVecVal* val); extern void e_bit121_1d(const svBitVecVal* val); @@ -93,7 +93,7 @@ extern "C" { extern void e_time_1d(const svLogicVecVal* val); extern void e_time_2d(const svLogicVecVal* val); extern void e_time_3d(const svLogicVecVal* val); - + // DPI IMPORTS extern void check_exports(); extern void* get_non_null(); @@ -177,7 +177,7 @@ extern "C" { extern void i_time_1d(const svLogicVecVal* val); extern void i_time_2d(const svLogicVecVal* val); extern void i_time_3d(const svLogicVecVal* val); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_output_type__Dpi.out b/test_regress/t/t_dpi_arg_output_type__Dpi.out index f2bc7f4c6..1a9db977f 100644 --- a/test_regress/t/t_dpi_arg_output_type__Dpi.out +++ b/test_regress/t/t_dpi_arg_output_type__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_array_2_state_1(svBitVecVal* o); extern void e_array_2_state_128(svBitVecVal* o); @@ -79,7 +79,7 @@ extern "C" { extern void e_union_4_state_33(svLogicVecVal* o); extern void e_union_4_state_64(svLogicVecVal* o); extern void e_union_4_state_65(svLogicVecVal* o); - + // DPI IMPORTS extern void check_exports(); extern void i_array_2_state_1(svBitVecVal* o); @@ -148,7 +148,7 @@ extern "C" { extern void i_union_4_state_33(svLogicVecVal* o); extern void i_union_4_state_64(svLogicVecVal* o); extern void i_union_4_state_65(svLogicVecVal* o); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_arg_output_unpack__Dpi.out b/test_regress/t/t_dpi_arg_output_unpack__Dpi.out index e3a2729a4..24675921e 100644 --- a/test_regress/t/t_dpi_arg_output_unpack__Dpi.out +++ b/test_regress/t/t_dpi_arg_output_unpack__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern void e_bit121_0d(svBitVecVal* val); extern void e_bit121_1d(svBitVecVal* val); @@ -93,7 +93,7 @@ extern "C" { extern void e_time_1d(svLogicVecVal* val); extern void e_time_2d(svLogicVecVal* val); extern void e_time_3d(svLogicVecVal* val); - + // DPI IMPORTS extern void check_exports(); extern void* get_non_null(); @@ -177,7 +177,7 @@ extern "C" { extern void i_time_1d(svLogicVecVal* val); extern void i_time_2d(svLogicVecVal* val); extern void i_time_3d(svLogicVecVal* val); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_dpi_result_type__Dpi.out b/test_regress/t/t_dpi_result_type__Dpi.out index e5d541f43..cd2d0ecc8 100644 --- a/test_regress/t/t_dpi_result_type__Dpi.out +++ b/test_regress/t/t_dpi_result_type__Dpi.out @@ -10,8 +10,8 @@ #ifdef __cplusplus extern "C" { #endif - - + + // DPI EXPORTS extern svBitVecVal e_array_2_state_1(); extern svBitVecVal e_array_2_state_32(); @@ -46,7 +46,7 @@ extern "C" { extern svBitVecVal e_union_2_state_1(); extern svBitVecVal e_union_2_state_32(); extern void e_void(); - + // DPI IMPORTS extern void check_exports(); extern svBitVecVal i_array_2_state_1(); @@ -82,7 +82,7 @@ extern "C" { extern svBitVecVal i_union_2_state_1(); extern svBitVecVal i_union_2_state_32(); extern void i_void(); - + #ifdef __cplusplus } #endif diff --git a/test_regress/t/t_emit_constw.v b/test_regress/t/t_emit_constw.v index e49d532de..ae9774734 100644 --- a/test_regress/t/t_emit_constw.v +++ b/test_regress/t/t_emit_constw.v @@ -62,7 +62,7 @@ module t (/*AUTOARG*/ ^ bytehash(w17)); // verilator lint_on WIDTH -`define EXPECTED_SUM 64'hb6fdb64085fc17f5 +`define EXPECTED_SUM 64'h2bc7c2a98a302891 // Test loop always @ (posedge clk) begin diff --git a/test_regress/t/t_extract_static_const.out b/test_regress/t/t_extract_static_const.out new file mode 100644 index 000000000..6b9780e61 --- /dev/null +++ b/test_regress/t/t_extract_static_const.out @@ -0,0 +1,9 @@ +0x88888888 +0x77777777 +0x66666666 +0x55555555 +0x44444444 +0x33333333 +0x22222222 +0x11111111 +*-* All Finished *-* diff --git a/test_regress/t/t_extract_static_const.pl b/test_regress/t/t_extract_static_const.pl new file mode 100755 index 000000000..63299d45f --- /dev/null +++ b/test_regress/t/t_extract_static_const.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 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_all => 1); + +compile( + verilator_flags2 => ["--stats"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, Prelim static constants extracted\s+(\d+)/i, + 1); + file_grep($Self->{stats}, qr/Optimizations, Prelim static constants reused\s+(\d+)/i, + 7); +} + +ok(1); +1; diff --git a/test_regress/t/t_extract_static_const.v b/test_regress/t/t_extract_static_const.v new file mode 100755 index 000000000..9cda8a26c --- /dev/null +++ b/test_regress/t/t_extract_static_const.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 Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + wire [255:0] C = {32'h1111_1111, + 32'h2222_2222, + 32'h3333_3333, + 32'h4444_4444, + 32'h5555_5555, + 32'h6666_6666, + 32'h7777_7777, + 32'h8888_8888}; + + initial begin + // Note: Base index via $c to prevent optimizatoin by Verilator + $display("0x%32x", C[$c(0*32)+:32]); + $display("0x%32x", C[$c(1*32)+:32]); + $display("0x%32x", C[$c(2*32)+:32]); + $display("0x%32x", C[$c(3*32)+:32]); + $display("0x%32x", C[$c(4*32)+:32]); + $display("0x%32x", C[$c(5*32)+:32]); + $display("0x%32x", C[$c(6*32)+:32]); + $display("0x%32x", C[$c(7*32)+:32]); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_extract_static_const_multimodule.out b/test_regress/t/t_extract_static_const_multimodule.out new file mode 100644 index 000000000..f739c8e51 --- /dev/null +++ b/test_regress/t/t_extract_static_const_multimodule.out @@ -0,0 +1,11 @@ +0x88888888 +0x66666666 +0x44444444 +0x22222222 +0x1111111122222222333333334444444455555555666666667777777788888888 +0x77777777 +0x55555555 +0x33333333 +0x11111111 +0x1111111122222222333333334444444455555555666666667777777788888888 +*-* All Finished *-* diff --git a/test_regress/t/t_extract_static_const_multimodule.pl b/test_regress/t/t_extract_static_const_multimodule.pl new file mode 100755 index 000000000..6767e6bcc --- /dev/null +++ b/test_regress/t/t_extract_static_const_multimodule.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 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_all => 1); + +compile( + verilator_flags2 => ["--stats"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, Prelim static constants extracted\s+(\d+)/i, + 2); + file_grep($Self->{stats}, qr/Optimizations, Prelim static constants reused\s+(\d+)/i, + 6); +} + +ok(1); +1; diff --git a/test_regress/t/t_extract_static_const_multimodule.v b/test_regress/t/t_extract_static_const_multimodule.v new file mode 100755 index 000000000..0f959991a --- /dev/null +++ b/test_regress/t/t_extract_static_const_multimodule.v @@ -0,0 +1,102 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +// +// Constants should not be shared by different non-inlined modules +// + +module a( + input wire clk, + input wire trig_i, + output reg trig_o + ); + /* verilator no_inline_module */ + + // Same constant as in module b + wire [255:0] C = {32'h1111_1111, + 32'h2222_2222, + 32'h3333_3333, + 32'h4444_4444, + 32'h5555_5555, + 32'h6666_6666, + 32'h7777_7777, + 32'h8888_8888}; + + always @(posedge clk) begin + trig_o <= 1'd0; + if (trig_i) begin + // Note: Base index via $c to prevent optimizatoin by Verilator + $display("0x%32x", C[$c(0*32)+:32]); + $display("0x%32x", C[$c(2*32)+:32]); + $display("0x%32x", C[$c(4*32)+:32]); + $display("0x%32x", C[$c(6*32)+:32]); + $display("0x%256x", C); + trig_o <= 1'd1; + end + end + +endmodule + +module b( + input wire clk, + input wire trig_i, + output reg trig_o + ); + /* verilator no_inline_module */ + + // Same constant as in module a + wire [255:0] C = {32'h1111_1111, + 32'h2222_2222, + 32'h3333_3333, + 32'h4444_4444, + 32'h5555_5555, + 32'h6666_6666, + 32'h7777_7777, + 32'h8888_8888}; + + always @(posedge clk) begin + trig_o <= 1'd0; + if (trig_i) begin + // Note: Base index via $c to prevent optimizatoin by Verilator + $display("0x%32x", C[$c(1*32)+:32]); + $display("0x%32x", C[$c(3*32)+:32]); + $display("0x%32x", C[$c(5*32)+:32]); + $display("0x%32x", C[$c(7*32)+:32]); + $display("0x%256x", C); + trig_o <= 1'd1; + end + end + +endmodule + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + integer cyc = 0; + + reg trig_i; + wire trig_ab; + wire trig_o; + + a a_inst(.clk(clk), .trig_i(trig_i), .trig_o(trig_ab)); + b b_inst(.clk(clk), .trig_i(trig_ab), .trig_o(trig_o)); + + always @(posedge clk) begin + trig_i <= cyc == 1; + + if (trig_o) begin + $write("*-* All Finished *-*\n"); + $finish; + end + + cyc++; + end + +endmodule diff --git a/test_regress/t/t_flag_expand_limit.pl b/test_regress/t/t_flag_expand_limit.pl new file mode 100755 index 000000000..6270f76ca --- /dev/null +++ b/test_regress/t/t_flag_expand_limit.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 2008 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 => ['--expand-limit 1 --stats'], + ); + +file_grep($Self->{stats}, qr/Optimizations, expand limited\s+(\d+)/i, 4); + +ok(1); +1; diff --git a/test_regress/t/t_flag_expand_limit.v b/test_regress/t/t_flag_expand_limit.v new file mode 100644 index 000000000..0640ce15a --- /dev/null +++ b/test_regress/t/t_flag_expand_limit.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, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// issue3005 + +module t #(parameter NV = 2000) + ( + input a, + input w1, + input [127:0] w2, + output [ 31:0] o, + + input [319:0] bi, + output [319:0] bo + ); + + // verilator lint_off WIDTH + wire [NV-1:0] d = a ? NV'(0) : {NV{w2}}; + // verilator lint_on WIDTH + assign o = d[31:0]; + + assign bo = ~bi; + +endmodule diff --git a/test_regress/t/t_flag_help.pl b/test_regress/t/t_flag_help.pl index f3dc0cca4..cb38bfb87 100755 --- a/test_regress/t/t_flag_help.pl +++ b/test_regress/t/t_flag_help.pl @@ -10,23 +10,33 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(dist => 1); +# See also t_flag_version.pl + +sub check { + my $interpreter = shift; + my $prog = shift; + + run(fails => 0, + cmd => [$interpreter, $prog, "--help"], + logfile => "$Self->{obj_dir}/t_help.log", + tee => 0, + verilator_run => 1, + ); + + file_grep("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i); +} + foreach my $prog ( - # See also t_flag_version.pl "../bin/verilator", "../bin/verilator_coverage", "../bin/verilator_difftree", "../bin/verilator_gantt", "../bin/verilator_profcfunc", ) { - run(fails => 0, - cmd => ["perl", $prog, - "--help"], - logfile => "$Self->{obj_dir}/t_help.log", - tee => 0, - verilator_run => 1, - ); - file_grep("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i); + check("perl", $prog); } +check("python3", "../bin/verilator_ccache_report"); + ok(1); 1; diff --git a/test_regress/t/t_func_crc.pl b/test_regress/t/t_func_crc.pl index 179c4c77d..6549284aa 100755 --- a/test_regress/t/t_func_crc.pl +++ b/test_regress/t/t_func_crc.pl @@ -19,7 +19,7 @@ execute( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 3870); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 3888); } ok(1); diff --git a/test_regress/t/t_func_uninit.pl b/test_regress/t/t_func_uninit.pl new file mode 100755 index 000000000..2cb5eeaff --- /dev/null +++ b/test_regress/t/t_func_uninit.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 2021 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_func_uninit.v b/test_regress/t/t_func_uninit.v new file mode 100644 index 000000000..c9eb85468 --- /dev/null +++ b/test_regress/t/t_func_uninit.v @@ -0,0 +1,33 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +function int zeroed; +endfunction + +function automatic integer what_bit; + input [31:0] a; + // what_bit = 0; + for (int i = 31; i >= 0; i = i - 1) begin + if (a[i] == 1'b1) begin + what_bit = i; + end + end +endfunction + +module t(/*AUTOARG*/); + + parameter ZERO = zeroed(); + + parameter PP = what_bit(0); + + initial begin + if (ZERO != 0) $stop; + if (PP != 'x) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_gate_ormux.pl b/test_regress/t/t_gate_ormux.pl index b4bc92497..996e05170 100755 --- a/test_regress/t/t_gate_ormux.pl +++ b/test_regress/t/t_gate_ormux.pl @@ -19,7 +19,7 @@ compile( ); if ($Self->{vlt}) { - file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 898); + file_grep($Self->{stats}, qr/Optimizations, Const bit op reduction\s+(\d+)/i, 994); } execute( diff --git a/test_regress/t/t_lint_latch_4.pl b/test_regress/t/t_lint_latch_4.pl new file mode 100755 index 000000000..629a44bbb --- /dev/null +++ b/test_regress/t/t_lint_latch_4.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-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(vlt => 1); + +lint( + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_latch_4.v b/test_regress/t/t_lint_latch_4.v new file mode 100644 index 000000000..e7182f4ca --- /dev/null +++ b/test_regress/t/t_lint_latch_4.v @@ -0,0 +1,27 @@ +// DESCRIPTION: Verilator: Verilog Test module for Issue#2938 +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2021 by Julien Margetts (Originally provided by YanJiun) + +module test ( + input [2:0] a, + input [3:0] c, + + output reg [7:0] b +); + + integer i; + + always @ (*) + begin + case(a) + {3'b000}: b = 8'd1; + {3'b001}: + for(i=0;i<4;i=i+1) b[i*2+:2] = 2'(c[i]); + {3'b010}: b = 8'd3; + {3'b011}: b = 8'd4; + default : b = 0; + endcase + end + +endmodule diff --git a/test_regress/t/t_lint_multidriven_bad.out b/test_regress/t/t_lint_multidriven_bad.out index ad7fb6500..231a2368c 100644 --- a/test_regress/t/t_lint_multidriven_bad.out +++ b/test_regress/t/t_lint_multidriven_bad.out @@ -1,17 +1,17 @@ %Warning-MULTIDRIVEN: t/t_lint_multidriven_bad.v:21:22: Signal has multiple driving blocks with different clocking: 't.mem' t/t_lint_multidriven_bad.v:27:7: ... Location of first driving block - 27 | mem[a0] <= d1; + 27 | mem[a0] <= d1; | ^~~ t/t_lint_multidriven_bad.v:24:7: ... Location of other driving block - 24 | mem[a0] <= d0; + 24 | mem[a0] <= d0; | ^~~ ... 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_multidriven_bad.v:19:22: Signal has multiple driving blocks with different clocking: 'out2' t/t_lint_multidriven_bad.v:35:7: ... Location of first driving block - 35 | out2[15:8] <= d0; + 35 | out2[15:8] <= d0; | ^~~~ t/t_lint_multidriven_bad.v:32:7: ... Location of other driving block - 32 | out2[7:0] <= d0; + 32 | out2[7:0] <= d0; | ^~~~ %Error: Exiting due to diff --git a/test_regress/t/t_lint_multidriven_bad.pl b/test_regress/t/t_lint_multidriven_bad.pl index a82cf66cb..32299029f 100755 --- a/test_regress/t/t_lint_multidriven_bad.pl +++ b/test_regress/t/t_lint_multidriven_bad.pl @@ -15,5 +15,15 @@ lint( expect_filename => $Self->{golden_filename}, ); +extract( + in => $Self->{top_filename}, + out => "../docs/gen/ex_MULTIDRIVEN_faulty.rst", + lines => "31-36"); + +extract( + in => $Self->{golden_filename}, + out => "../docs/gen/ex_MULTIDRIVEN_msg.rst", + lines => "10,11,14"); + ok(1); 1; diff --git a/test_regress/t/t_lint_multidriven_bad.v b/test_regress/t/t_lint_multidriven_bad.v index 19d4e86e1..d9f68bdf1 100644 --- a/test_regress/t/t_lint_multidriven_bad.v +++ b/test_regress/t/t_lint_multidriven_bad.v @@ -21,18 +21,18 @@ module t (/*AUTOARG*/ reg [7:0] mem [4]; always @(posedge clk) begin - mem[a0] <= d0; + mem[a0] <= d0; // <--- Warning end always @(negedge clk) begin - mem[a0] <= d1; + mem[a0] <= d1; // <--- Warning end assign out = {mem[3],mem[2],mem[1],mem[0]}; always @(posedge clk) begin - out2[7:0] <= d0; + out2[7:0] <= d0; // <--- Warning end always @(negedge clk) begin - out2[15:8] <= d0; + out2[15:8] <= d0; // <--- Warning end endmodule diff --git a/test_regress/t/t_lint_pragma_protected.pl b/test_regress/t/t_lint_pragma_protected.pl new file mode 100755 index 000000000..26a2c09ae --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected.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 2021 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 -Wno-PROTECTED'], + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_pragma_protected.v b/test_regress/t/t_lint_pragma_protected.v new file mode 100644 index 000000000..dc8eb4cad --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected.v @@ -0,0 +1,48 @@ +// This part should pass OK + +module t_lint_pragma_protected; + +`pragma protect begin_protected +`pragma protect version=1 +`pragma protect encrypt_agent="XXXXX" +`pragma protect encrypt_agent_info="YYYYY" +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 64) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`pragma protect end_protected + +endmodule diff --git a/test_regress/t/t_lint_pragma_protected_err.out b/test_regress/t/t_lint_pragma_protected_err.out new file mode 100644 index 000000000..2e5922f37 --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected_err.out @@ -0,0 +1,17 @@ +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:8:17: Unknown '`pragma protect' error + 8 | `pragma protect encrypt_agent=123 + | ^~~~~~~~~~~~~~~~~ + ... For error description see https://verilator.org/warn/BADSTDPRAGMA?v=latest +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:10:17: Unknown '`pragma protect' error + 10 | `pragma protect encrypt_agent_info + | ^~~~~~~~~~~~~~~~~~ +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:23:1: BASE64 encoding length mismatch in `pragma protect key_bloock/data_block +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:27:17: multiple `pragma protected encoding sections + 27 | `pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +%Warning-PROTECTED: t/t_lint_pragma_protected_err.v:44:17: A '`pragma protected data_block' encrypted section was detected and will be skipped. + ... Use "/* verilator lint_off PROTECTED */" and lint_on around source to disable this message. +%Error-BADSTDPRAGMA: t/t_lint_pragma_protected_err.v:58:1: `pragma is missing a pragma_expression. + 58 | `pragma + | ^~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_lint_pragma_protected_err.pl b/test_regress/t/t_lint_pragma_protected_err.pl new file mode 100755 index 000000000..ad84f1b54 --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected_err.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 2021 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, + verilator_flags2 => ['--lint-only -Wpedantic'], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_lint_pragma_protected_err.v b/test_regress/t/t_lint_pragma_protected_err.v new file mode 100644 index 000000000..5e761c364 --- /dev/null +++ b/test_regress/t/t_lint_pragma_protected_err.v @@ -0,0 +1,60 @@ +module t_lint_pragma_protected_err; + +// This part should see some failures + +`pragma protect begin_protected +`pragma protect version="xx" +// should fail because value should be quoted +`pragma protect encrypt_agent=123 +// should fail because no value given at all +`pragma protect encrypt_agent_info +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" + +// expect error in key_block below, 64 bytes but expecting 65 +// also expect "multiple `pragma encoding sections` error because number of +// bytes does not go down to 0 in the end of the section below due to the 64->65 change +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 65) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`pragma protect end_protected + +// Should trigger unknown pragma warning, although in principle unknown pragmas should be safely ignored. +`pragma XXXXX + +// Should trigger missing pragma warning +`pragma + +endmodule diff --git a/test_regress/t/t_no_sel_assign_merge_in_cpp.pl b/test_regress/t/t_no_sel_assign_merge_in_cpp.pl new file mode 100755 index 000000000..72441b2f8 --- /dev/null +++ b/test_regress/t/t_no_sel_assign_merge_in_cpp.pl @@ -0,0 +1,16 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2021 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); + +lint(); + +ok(1); +1; diff --git a/test_regress/t/t_no_sel_assign_merge_in_cpp.v b/test_regress/t/t_no_sel_assign_merge_in_cpp.v new file mode 100644 index 000000000..6c7f1a62b --- /dev/null +++ b/test_regress/t/t_no_sel_assign_merge_in_cpp.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, 2021 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t_no_sel_assign_merge_in_cpp ( + input wire [(8*39)-1:0] d_i, + output wire [(8*32)-1:0] d_o +); + for (genvar i = 0; i < 8; i = i + 1) begin + assign d_o[i*32 +: 32] = d_i[i*39 +: 32]; + end +endmodule diff --git a/test_regress/t/t_pp_pragma_bad.out b/test_regress/t/t_pp_pragma_bad.out index 912313652..713607531 100644 --- a/test_regress/t/t_pp_pragma_bad.out +++ b/test_regress/t/t_pp_pragma_bad.out @@ -1,6 +1,7 @@ -%Error: t/t_pp_pragma_bad.v:7:1: `pragma is missing a pragma_expression. +%Error-BADSTDPRAGMA: t/t_pp_pragma_bad.v:7:1: `pragma is missing a pragma_expression. 7 | `pragma | ^~~~~~~ + ... For error description see https://verilator.org/warn/BADSTDPRAGMA?v=latest `line 1 "t/t_pp_pragma_bad.v" 1 diff --git a/test_regress/t/t_preproc.out b/test_regress/t/t_preproc.out index db7c40637..376c8eb4b 100644 --- a/test_regress/t/t_preproc.out +++ b/test_regress/t/t_preproc.out @@ -274,6 +274,62 @@ endmodule `line 164 "t/t_preproc.v" 0 +module t_lint_pragma_protected; + +`line 168 "t/t_preproc.v" 0 +`pragma protect begin_protected +`pragma protect version=1 +`pragma protect encrypt_agent="XXXXX" +`pragma protect encrypt_agent_info="YYYYY" +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 64) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`line 181 "t/t_preproc.v" 0 +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`line 190 "t/t_preproc.v" 0 +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`line 199 "t/t_preproc.v" 0 +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`line 209 "t/t_preproc.v" 0 +`pragma protect end_protected + +`line 211 "t/t_preproc.v" 0 +endmodule + +`line 213 "t/t_preproc.v" 0 + + @@ -282,17 +338,17 @@ endmodule -`line 174 "t/t_preproc.v" 0 +`line 223 "t/t_preproc.v" 0 begin addr <= (({regs[6], regs[7]} + 1)); rd <= 1; end and begin addr <= (({regs[6], regs[7]})); wdata <= (rdata); wr <= 1; end begin addr <= ({regs[6], regs[7]} + 1); rd <= 1; end begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more -`line 178 "t/t_preproc.v" 0 +`line 227 "t/t_preproc.v" 0 -`line 181 "t/t_preproc.v" 0 +`line 230 "t/t_preproc.v" 0 `line 1 "t/t_preproc_inc4.vh" 1 `line 2 "t/t_preproc_inc4.vh" 0 @@ -304,57 +360,57 @@ begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more `line 8 "t/t_preproc_inc4.vh" 2 -`line 181 "t/t_preproc.v" 0 +`line 230 "t/t_preproc.v" 0 -`line 182 "t/t_preproc.v" 0 +`line 231 "t/t_preproc.v" 0 -`line 185 "t/t_preproc.v" 0 +`line 234 "t/t_preproc.v" 0 -`line 187 "t/t_preproc.v" 0 +`line 236 "t/t_preproc.v" 0 -`line 191 "t/t_preproc.v" 0 +`line 240 "t/t_preproc.v" 0 -`line 194 "t/t_preproc.v" 0 +`line 243 "t/t_preproc.v" 0 $blah("ab,cd","e,f"); $blah(this.logfile,vec); $blah(this.logfile,vec[1,2,3]); $blah(this.logfile,{blah.name(), " is not foo"}); -`line 200 "t/t_preproc.v" 0 +`line 249 "t/t_preproc.v" 0 -`line 203 "t/t_preproc.v" 0 +`line 252 "t/t_preproc.v" 0 `pragma foo = 1 `default_nettype none `default_nettype uwire -`line 207 "t/t_preproc.v" 0 +`line 256 "t/t_preproc.v" 0 -`line 210 "t/t_preproc.v" 0 +`line 259 "t/t_preproc.v" 0 -`line 214 "t/t_preproc.v" 0 -Line_Preproc_Check 214 +`line 263 "t/t_preproc.v" 0 +Line_Preproc_Check 263 -`line 216 "t/t_preproc.v" 0 +`line 265 "t/t_preproc.v" 0 -`line 219 "t/t_preproc.v" 0 +`line 268 "t/t_preproc.v" 0 @@ -362,15 +418,15 @@ Line_Preproc_Check 214 -`line 226 "t/t_preproc.v" 0 +`line 275 "t/t_preproc.v" 0 (x,y) -Line_Preproc_Check 227 +Line_Preproc_Check 276 -`line 229 "t/t_preproc.v" 0 +`line 278 "t/t_preproc.v" 0 -`line 232 "t/t_preproc.v" 0 +`line 281 "t/t_preproc.v" 0 @@ -379,17 +435,17 @@ beginend beginend "beginend" -`line 240 "t/t_preproc.v" 0 +`line 289 "t/t_preproc.v" 0 `\esc`def -`line 246 "t/t_preproc.v" 0 +`line 295 "t/t_preproc.v" 0 Not a \`define -`line 248 "t/t_preproc.v" 0 +`line 297 "t/t_preproc.v" 0 @@ -398,123 +454,26 @@ Not a \`define x,y)--bee submacro has comma paren -`line 256 "t/t_preproc.v" 0 +`line 305 "t/t_preproc.v" 0 $display("10 %d %d", $bits(foo), 10); -`line 261 "t/t_preproc.v" 0 - - - - - -`line 266 "t/t_preproc.v" 0 - - - -`line 269 "t/t_preproc.v" 0 - - - - - - - - - - - - - - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - -`line 283 "t/t_preproc.v" 0 - assign a3 = ~b3 ; -`line 283 "t/t_preproc.v" 0 - - -`line 285 "t/t_preproc.v" 0 - - \ - - - - - - - - -`line 294 "t/t_preproc.v" 0 - -`line 294 "t/t_preproc.v" 0 - -`line 294 "t/t_preproc.v" 0 - def i - - -`line 296 "t/t_preproc.v" 0 - - -`line 298 "t/t_preproc.v" 0 - - - - - -`line 302 "t/t_preproc.v" 0 - - - - - - -`line 308 "t/t_preproc.v" 0 -1 /*verilator NOT IN DEFINE*/ (nodef) -2 /*verilator PART OF DEFINE*/ (hasdef) -3 `line 310 "t/t_preproc.v" 0 -/*verilator NOT PART - OF DEFINE*/ (nodef) -`line 311 "t/t_preproc.v" 0 -4 -`line 311 "t/t_preproc.v" 0 -/*verilator PART - OF DEFINE*/ (nodef) -`line 312 "t/t_preproc.v" 0 -5 also in -`line 312 "t/t_preproc.v" 0 - also3 (nodef) + + + -HAS a NEW `line 315 "t/t_preproc.v" 0 -LINE + + -`line 317 "t/t_preproc.v" 0 +`line 318 "t/t_preproc.v" 0 + - -`line 319 "t/t_preproc.v" 0 - @@ -527,10 +486,107 @@ LINE `line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + +`line 332 "t/t_preproc.v" 0 + assign a3 = ~b3 ; +`line 332 "t/t_preproc.v" 0 + + +`line 334 "t/t_preproc.v" 0 + + \ -`line 335 "t/t_preproc.v" 0 + + + + + +`line 343 "t/t_preproc.v" 0 + +`line 343 "t/t_preproc.v" 0 + +`line 343 "t/t_preproc.v" 0 + def i + + +`line 345 "t/t_preproc.v" 0 + + +`line 347 "t/t_preproc.v" 0 + + + + + +`line 351 "t/t_preproc.v" 0 + + + + + + +`line 357 "t/t_preproc.v" 0 +1 /*verilator NOT IN DEFINE*/ (nodef) +2 /*verilator PART OF DEFINE*/ (hasdef) +3 +`line 359 "t/t_preproc.v" 0 +/*verilator NOT PART + OF DEFINE*/ (nodef) +`line 360 "t/t_preproc.v" 0 +4 +`line 360 "t/t_preproc.v" 0 +/*verilator PART + OF DEFINE*/ (nodef) +`line 361 "t/t_preproc.v" 0 +5 also in +`line 361 "t/t_preproc.v" 0 + also3 (nodef) + + +HAS a NEW +`line 364 "t/t_preproc.v" 0 +LINE + +`line 366 "t/t_preproc.v" 0 + + +`line 368 "t/t_preproc.v" 0 + + + + + + + + + + + + + +`line 381 "t/t_preproc.v" 0 + + + +`line 384 "t/t_preproc.v" 0 EXP: clxx_scen clxx_scen EXP: clxx_scen @@ -538,44 +594,44 @@ EXP: clxx_scen EXP: do if (start("verilog/inc1.v", 25)) begin message({"Blah-", "clx_scen", " end"}); end while(0); -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 do -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 - if (start("t/t_preproc.v", 341)) begin -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 + if (start("t/t_preproc.v", 390)) begin +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 message({"Blah-", "clx_scen", " end"}); -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 end -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 while(0); -`line 343 "t/t_preproc.v" 0 +`line 392 "t/t_preproc.v" 0 -`line 345 "t/t_preproc.v" 0 +`line 394 "t/t_preproc.v" 0 -`line 349 "t/t_preproc.v" 0 +`line 398 "t/t_preproc.v" 0 -`line 349 "t/t_preproc.v" 0 +`line 398 "t/t_preproc.v" 0 -`line 350 "t/t_preproc.v" 0 +`line 399 "t/t_preproc.v" 0 EXP: This is fooed @@ -583,7 +639,7 @@ This is fooed EXP: This is fooed_2 This is fooed_2 -`line 357 "t/t_preproc.v" 0 +`line 406 "t/t_preproc.v" 0 np @@ -595,11 +651,11 @@ np -`line 368 "t/t_preproc.v" 0 +`line 417 "t/t_preproc.v" 0 -`line 371 "t/t_preproc.v" 0 +`line 420 "t/t_preproc.v" 0 @@ -608,12 +664,12 @@ np -`line 379 "t/t_preproc.v" 0 +`line 428 "t/t_preproc.v" 0 -`line 383 "t/t_preproc.v" 0 +`line 432 "t/t_preproc.v" 0 hello3hello3hello3 hello4hello4hello4hello4 @@ -621,7 +677,7 @@ hello4hello4hello4hello4 -`line 389 "t/t_preproc.v" 0 +`line 438 "t/t_preproc.v" 0 `line 1 "t/t_preproc_inc4.vh" 1 `line 2 "t/t_preproc_inc4.vh" 0 @@ -633,9 +689,9 @@ hello4hello4hello4hello4 `line 8 "t/t_preproc_inc4.vh" 2 -`line 389 "t/t_preproc.v" 0 +`line 438 "t/t_preproc.v" 0 -`line 390 "t/t_preproc.v" 0 +`line 439 "t/t_preproc.v" 0 @@ -645,28 +701,28 @@ hello4hello4hello4hello4 -`line 398 "t/t_preproc.v" 0 +`line 447 "t/t_preproc.v" 0 -Line_Preproc_Check 402 +Line_Preproc_Check 451 -Line_Preproc_Check 408 +Line_Preproc_Check 457 "FOO \ BAR " "arg_line1 \ arg_line2" "FOO \ BAR " -`line 411 "t/t_preproc.v" 0 -Line_Preproc_Check 411 +`line 460 "t/t_preproc.v" 0 +Line_Preproc_Check 460 -`line 415 "t/t_preproc.v" 0 +`line 464 "t/t_preproc.v" 0 @@ -677,14 +733,14 @@ abc -`line 425 "t/t_preproc.v" 0 +`line 474 "t/t_preproc.v" 0 EXP: sonet_frame sonet_frame -`line 431 "t/t_preproc.v" 0 +`line 480 "t/t_preproc.v" 0 EXP: sonet_frame @@ -695,7 +751,7 @@ sonet_frame EXP: sonet_frame sonet_frame -`line 441 "t/t_preproc.v" 0 +`line 490 "t/t_preproc.v" 0 @@ -703,13 +759,13 @@ EXP: module zzz ; endmodule module zzz ; endmodule module zzz ; endmodule -`line 448 "t/t_preproc.v" 0 +`line 497 "t/t_preproc.v" 0 EXP: module a_b ; endmodule module a_b ; endmodule module a_b ; endmodule -`line 453 "t/t_preproc.v" 0 +`line 502 "t/t_preproc.v" 0 integer foo; @@ -723,7 +779,7 @@ module t; initial begin : \`LEX_CAT(a[0],_assignment) -`line 465 "t/t_preproc.v" 0 +`line 514 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`LEX_CAT(a[0],_assignment) "); end @@ -732,7 +788,7 @@ module t; initial begin : \a[0]_assignment_a[1] -`line 472 "t/t_preproc.v" 0 +`line 521 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\a[0]_assignment_a[1] "); end @@ -748,7 +804,7 @@ module t; initial begin : \`CAT(ff,bb) -`line 486 "t/t_preproc.v" 0 +`line 535 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`CAT(ff,bb) "); end @@ -756,7 +812,7 @@ module t; initial begin : \`zzz -`line 492 "t/t_preproc.v" 0 +`line 541 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`zzz "); end @@ -765,11 +821,11 @@ module t; initial begin : \`FOO -`line 499 "t/t_preproc.v" 0 +`line 548 "t/t_preproc.v" 0 $write("GOT%%m='%m' OTHER_EXP='%s'\n OUR_EXP='%s'", "t.bar ","t.\\`FOO "); end initial begin : \xx`FOO -`line 501 "t/t_preproc.v" 0 +`line 550 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\xx`FOO "); end @@ -802,27 +858,27 @@ module t; initial -`line 532 "t/t_preproc.v" 0 +`line 581 "t/t_preproc.v" 0 $display("%s%s","a1","b2c3\n"); endmodule -`line 535 "t/t_preproc.v" 0 +`line 584 "t/t_preproc.v" 0 -`line 538 "t/t_preproc.v" 0 +`line 587 "t/t_preproc.v" 0 $display("RAM0"); $display("CPU"); -`line 543 "t/t_preproc.v" 0 +`line 592 "t/t_preproc.v" 0 -`line 548 "t/t_preproc.v" 0 +`line 597 "t/t_preproc.v" 0 XXE_FAMILY = XXE_ @@ -830,7 +886,7 @@ XXE_FAMILY = XXE_ $display("XXE_ is defined"); -`line 555 "t/t_preproc.v" 0 +`line 604 "t/t_preproc.v" 0 XYE_FAMILY = XYE_ @@ -838,7 +894,7 @@ XYE_FAMILY = XYE_ $display("XYE_ is defined"); -`line 562 "t/t_preproc.v" 0 +`line 611 "t/t_preproc.v" 0 XXS_FAMILY = XXS_some @@ -846,7 +902,7 @@ XXS_FAMILY = XXS_some $display("XXS_some is defined"); -`line 569 "t/t_preproc.v" 0 +`line 618 "t/t_preproc.v" 0 XYS_FAMILY = XYS_foo @@ -854,10 +910,10 @@ XYS_FAMILY = XYS_foo $display("XYS_foo is defined"); -`line 576 "t/t_preproc.v" 0 +`line 625 "t/t_preproc.v" 0 -`line 578 "t/t_preproc.v" 0 +`line 627 "t/t_preproc.v" 0 @@ -866,7 +922,7 @@ XYS_FAMILY = XYS_foo -`line 586 "t/t_preproc.v" 0 +`line 635 "t/t_preproc.v" 0 @@ -874,7 +930,7 @@ XYS_FAMILY = XYS_foo -`line 593 "t/t_preproc.v" 0 +`line 642 "t/t_preproc.v" 0 @@ -882,7 +938,7 @@ XYS_FAMILY = XYS_foo -`line 600 "t/t_preproc.v" 0 +`line 649 "t/t_preproc.v" 0 @@ -890,26 +946,26 @@ XYS_FAMILY = XYS_foo -`line 607 "t/t_preproc.v" 0 +`line 656 "t/t_preproc.v" 0 -`line 609 "t/t_preproc.v" 0 +`line 658 "t/t_preproc.v" 0 -`line 611 "t/t_preproc.v" 0 +`line 660 "t/t_preproc.v" 0 (.mySig (myInterface.pa5), -`line 615 "t/t_preproc.v" 0 +`line 664 "t/t_preproc.v" 0 -`line 618 "t/t_preproc.v" 0 +`line 667 "t/t_preproc.v" 0 `dbg_hdl(UVM_LOW, ("Functional coverage enabled: paramgrp")); -`line 621 "t/t_preproc.v" 0 +`line 670 "t/t_preproc.v" 0 @@ -918,28 +974,28 @@ XYS_FAMILY = XYS_foo -`line 629 "t/t_preproc.v" 0 +`line 678 "t/t_preproc.v" 0 module pcc2_cfg; generate -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 covergroup a @(posedge b); -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 c: coverpoint d iff ((c) === 1'b1); endgroup -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 a u_a; -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 initial do begin $display ("DEBUG : %s [%m]", $sformatf ("Functional coverage enabled: u_a")); end while(0); endgenerate endmodule -`line 635 "t/t_preproc.v" 0 +`line 684 "t/t_preproc.v" 0 "`NOT_DEFINED_STR" -`line 640 "t/t_preproc.v" 0 +`line 689 "t/t_preproc.v" 0 @@ -962,4 +1018,4 @@ predef 2 2 -`line 662 "t/t_preproc.v" 2 +`line 711 "t/t_preproc.v" 2 diff --git a/test_regress/t/t_preproc.v b/test_regress/t/t_preproc.v index 31d7ab17f..a52ce02c1 100644 --- a/test_regress/t/t_preproc.v +++ b/test_regress/t/t_preproc.v @@ -161,6 +161,55 @@ module prot(); endmodule //" +//====================================================================== +// Check IEEE1800-2017 `pragma protect encrypted modules +module t_lint_pragma_protected; + +`pragma protect begin_protected +`pragma protect version=1 +`pragma protect encrypt_agent="XXXXX" +`pragma protect encrypt_agent_info="YYYYY" +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 64) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`pragma protect end_protected + +endmodule + //====================================================================== // macro call with define that has comma `define REG_H 6 diff --git a/test_regress/t/t_preproc_comments.out b/test_regress/t/t_preproc_comments.out index 158faa511..1d2795895 100644 --- a/test_regress/t/t_preproc_comments.out +++ b/test_regress/t/t_preproc_comments.out @@ -273,6 +273,62 @@ endmodule `line 164 "t/t_preproc.v" 0 //====================================================================== +// Check IEEE1800-2017 `pragma protect encrypted modules +module t_lint_pragma_protected; + +`line 168 "t/t_preproc.v" 0 +`pragma protect begin_protected +`pragma protect version=1 +`pragma protect encrypt_agent="XXXXX" +`pragma protect encrypt_agent_info="YYYYY" +`pragma protect data_method="AES128-CBC" +`pragma protect key_keyowner="BIG3#1" +`pragma protect key_keyname="AAAAAA" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 64) +`pragma protect key_block +ICAgICAgICAgICAgICAgICAgIEdOVSBMRVNTRVIgR0VORVJBTCBQVUJMSUMgTElDRU5TRQogICAg +KSAyMDA3IE== + +`line 181 "t/t_preproc.v" 0 +`pragma protect key_keyowner="BIG3#2" +`pragma protect key_keyname="BBBBBB" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +IEV2ZXJ5b25lIGlzIHBlcm1pdHRlZCB0byBjb3B5IGFuZCBkaXN0cmlidXRlIHZlcmJhdGltIGNv +cGllcwogb2YgdGhpcyBsaWNlbnNlIGRvY3VtZW50LCBidXQgY2hhbmdpbmcgaXQgaXMgbm90IGFs +bG93ZWQuCgoKICBUaGl= + +`line 190 "t/t_preproc.v" 0 +`pragma protect key_keyowner="BIG3#3" +`pragma protect key_keyname="CCCCCCCC" +`pragma protect key_method="RSA" +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 128) +`pragma protect key_block +TGljZW5zZSBpbmNvcnBvcmF0ZXMKdGhlIHRlcm1zIGFuZCBjb25kaXRpb25zIG9mIHZlcnNpb24g +MyBvZiB0aGUgR05VIEdlbmVyYWwgUHVibGljCkxpY2Vuc2UsIHN1cHBsZW1lbnRlZCBieSB0aGUg +YWRkaXRpb25hbCBwZXJ= + +`line 199 "t/t_preproc.v" 0 +`pragma protect encoding = (enctype = "BASE64", line_length = 76, bytes = 295) +`pragma protect data_block +aW5pdGlvbnMuCgogIEFzIHVzZWQgaGVyZWluLCAidGhpcyBMaWNlbnNlIiByZWZlcnMgdG8gdmVy +c2lvbiAzIG9mIHRoZSBHTlUgTGVzc2VyCkdlbmVyYWwgUHVibGljIExpY2Vuc2UsIGFuZCB0aGUg +IkdOVSBHUEwiIHJlZmVycyB0byB2ZXJzaW9uIDMgb2YgdGhlIEdOVQpHZW5lcmFsIFB1YmxpYyBM +aWNlbnNlLgoKICAiVGhlIExpYnJhcnkiIHJlZmVycyB0byBhIGNvdmVyZWQgd29yayBnb3Zlcm5l +ZCBieSB0aGlzIExpY2Vuc2UsCm90aGVyIHRoYW4gYW4gQXBwbGljYXRpb24gb3IgYSBDb21iaW5l +ZCBXb3JrIGFzIG== + + +`line 209 "t/t_preproc.v" 0 +`pragma protect end_protected + +`line 211 "t/t_preproc.v" 0 +endmodule + +`line 213 "t/t_preproc.v" 0 +//====================================================================== // macro call with define that has comma @@ -282,17 +338,17 @@ endmodule -`line 174 "t/t_preproc.v" 0 +`line 223 "t/t_preproc.v" 0 begin addr <= (({regs[6], regs[7]} + 1)); rd <= 1; end and begin addr <= (({regs[6], regs[7]})); wdata <= (rdata); wr <= 1; end begin addr <= ({regs[6], regs[7]} + 1); rd <= 1; end begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more -`line 178 "t/t_preproc.v" 0 +`line 227 "t/t_preproc.v" 0 //====================================================================== // include of parameterized file -`line 181 "t/t_preproc.v" 0 +`line 230 "t/t_preproc.v" 0 `line 1 "t/t_preproc_inc4.vh" 1 // DESCRIPTION: Verilog::Preproc: Example source code `line 2 "t/t_preproc_inc4.vh" 0 @@ -304,57 +360,57 @@ begin addr <= ({regs[6], regs[7]}); wdata <= (rdata); wr <= 1; end more `line 8 "t/t_preproc_inc4.vh" 2 -`line 181 "t/t_preproc.v" 0 +`line 230 "t/t_preproc.v" 0 -`line 182 "t/t_preproc.v" 0 +`line 231 "t/t_preproc.v" 0 -`line 185 "t/t_preproc.v" 0 +`line 234 "t/t_preproc.v" 0 -`line 187 "t/t_preproc.v" 0 +`line 236 "t/t_preproc.v" 0 -`line 191 "t/t_preproc.v" 0 +`line 240 "t/t_preproc.v" 0 //====================================================================== // macro call with , in {} -`line 194 "t/t_preproc.v" 0 +`line 243 "t/t_preproc.v" 0 $blah("ab,cd","e,f"); $blah(this.logfile,vec); $blah(this.logfile,vec[1,2,3]); $blah(this.logfile,{blah.name(), " is not foo"}); -`line 200 "t/t_preproc.v" 0 +`line 249 "t/t_preproc.v" 0 //====================================================================== // pragma/default net type -`line 203 "t/t_preproc.v" 0 +`line 252 "t/t_preproc.v" 0 `pragma foo = 1 `default_nettype none `default_nettype uwire -`line 207 "t/t_preproc.v" 0 +`line 256 "t/t_preproc.v" 0 //====================================================================== // Ifdef -`line 210 "t/t_preproc.v" 0 +`line 259 "t/t_preproc.v" 0 -`line 214 "t/t_preproc.v" 0 -Line_Preproc_Check 214 +`line 263 "t/t_preproc.v" 0 +Line_Preproc_Check 263 -`line 216 "t/t_preproc.v" 0 +`line 265 "t/t_preproc.v" 0 //====================================================================== // bug84 -`line 219 "t/t_preproc.v" 0 +`line 268 "t/t_preproc.v" 0 // Hello, comments MIGHT not be legal /*more,,)cmts*/ // But newlines ARE legal... who speced THAT? @@ -362,15 +418,15 @@ Line_Preproc_Check 214 -`line 226 "t/t_preproc.v" 0 +`line 275 "t/t_preproc.v" 0 (//Here x,y //Too) -Line_Preproc_Check 227 +Line_Preproc_Check 276 -`line 229 "t/t_preproc.v" 0 +`line 278 "t/t_preproc.v" 0 //====================================================================== // defines split arguments -`line 232 "t/t_preproc.v" 0 +`line 281 "t/t_preproc.v" 0 @@ -379,17 +435,17 @@ beginend // 2001 spec doesn't require two tokens, so "beginend" ok beginend // 2001 spec doesn't require two tokens, so "beginend" ok "beginend" // No space "beginend" -`line 240 "t/t_preproc.v" 0 +`line 289 "t/t_preproc.v" 0 //====================================================================== // bug106 `\esc`def -`line 246 "t/t_preproc.v" 0 +`line 295 "t/t_preproc.v" 0 Not a \`define -`line 248 "t/t_preproc.v" 0 +`line 297 "t/t_preproc.v" 0 //====================================================================== // misparsed comma in submacro @@ -398,23 +454,23 @@ Not a \`define x,y)--bee submacro has comma paren -`line 256 "t/t_preproc.v" 0 +`line 305 "t/t_preproc.v" 0 //====================================================================== // bug191 $display("10 %d %d", $bits(foo), 10); -`line 261 "t/t_preproc.v" 0 +`line 310 "t/t_preproc.v" 0 //====================================================================== // 1800-2009 -`line 266 "t/t_preproc.v" 0 +`line 315 "t/t_preproc.v" 0 -`line 269 "t/t_preproc.v" 0 +`line 318 "t/t_preproc.v" 0 //====================================================================== // bug202 @@ -429,34 +485,34 @@ $display("10 %d %d", $bits(foo), 10); -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 assign a3 = ~b3 ; -`line 283 "t/t_preproc.v" 0 +`line 332 "t/t_preproc.v" 0 -`line 285 "t/t_preproc.v" 0 +`line 334 "t/t_preproc.v" 0 /* multi \ line1*/ \ -`line 287 "t/t_preproc.v" 0 +`line 336 "t/t_preproc.v" 0 /*multi \ line2*/ @@ -465,59 +521,59 @@ $display("10 %d %d", $bits(foo), 10); -`line 294 "t/t_preproc.v" 0 +`line 343 "t/t_preproc.v" 0 -`line 294 "t/t_preproc.v" 0 +`line 343 "t/t_preproc.v" 0 -`line 294 "t/t_preproc.v" 0 +`line 343 "t/t_preproc.v" 0 /* multi line 3*/ -`line 294 "t/t_preproc.v" 0 +`line 343 "t/t_preproc.v" 0 def i -`line 296 "t/t_preproc.v" 0 +`line 345 "t/t_preproc.v" 0 //====================================================================== -`line 298 "t/t_preproc.v" 0 +`line 347 "t/t_preproc.v" 0 -`line 302 "t/t_preproc.v" 0 +`line 351 "t/t_preproc.v" 0 -`line 308 "t/t_preproc.v" 0 +`line 357 "t/t_preproc.v" 0 1 // verilator NOT IN DEFINE (nodef) 2 /* verilator PART OF DEFINE */ (hasdef) 3 -`line 310 "t/t_preproc.v" 0 +`line 359 "t/t_preproc.v" 0 /* verilator NOT PART OF DEFINE */ (nodef) -`line 311 "t/t_preproc.v" 0 +`line 360 "t/t_preproc.v" 0 4 -`line 311 "t/t_preproc.v" 0 +`line 360 "t/t_preproc.v" 0 /* verilator PART OF DEFINE */ (nodef) -`line 312 "t/t_preproc.v" 0 +`line 361 "t/t_preproc.v" 0 5 also in -`line 312 "t/t_preproc.v" 0 +`line 361 "t/t_preproc.v" 0 also3 // CMT NOT (nodef) HAS a NEW -`line 315 "t/t_preproc.v" 0 +`line 364 "t/t_preproc.v" 0 LINE -`line 317 "t/t_preproc.v" 0 +`line 366 "t/t_preproc.v" 0 //====================================================================== -`line 319 "t/t_preproc.v" 0 +`line 368 "t/t_preproc.v" 0 @@ -531,11 +587,11 @@ LINE -`line 332 "t/t_preproc.v" 0 +`line 381 "t/t_preproc.v" 0 -`line 335 "t/t_preproc.v" 0 +`line 384 "t/t_preproc.v" 0 EXP: clxx_scen clxx_scen EXP: clxx_scen @@ -543,44 +599,44 @@ EXP: clxx_scen EXP: do if (start("verilog/inc1.v", 25)) begin message({"Blah-", "clx_scen", " end"}); end while(0); -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 do -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 /* synopsys translate_off */ -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 - if (start("t/t_preproc.v", 341)) begin -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 + if (start("t/t_preproc.v", 390)) begin +`line 390 "t/t_preproc.v" 0 -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 message({"Blah-", "clx_scen", " end"}); -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 end -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 /* synopsys translate_on */ -`line 341 "t/t_preproc.v" 0 +`line 390 "t/t_preproc.v" 0 while(0); -`line 343 "t/t_preproc.v" 0 +`line 392 "t/t_preproc.v" 0 //====================================================================== -`line 345 "t/t_preproc.v" 0 +`line 394 "t/t_preproc.v" 0 -`line 349 "t/t_preproc.v" 0 +`line 398 "t/t_preproc.v" 0 -`line 349 "t/t_preproc.v" 0 +`line 398 "t/t_preproc.v" 0 -`line 350 "t/t_preproc.v" 0 +`line 399 "t/t_preproc.v" 0 //`ifndef def_fooed_2 `error "No def_fooed_2" `endif EXP: This is fooed @@ -588,7 +644,7 @@ This is fooed EXP: This is fooed_2 This is fooed_2 -`line 357 "t/t_preproc.v" 0 +`line 406 "t/t_preproc.v" 0 //====================================================================== np @@ -600,11 +656,11 @@ np -`line 368 "t/t_preproc.v" 0 +`line 417 "t/t_preproc.v" 0 -`line 371 "t/t_preproc.v" 0 +`line 420 "t/t_preproc.v" 0 //====================================================================== // Metaprogramming @@ -613,12 +669,12 @@ np -`line 379 "t/t_preproc.v" 0 +`line 428 "t/t_preproc.v" 0 -`line 383 "t/t_preproc.v" 0 +`line 432 "t/t_preproc.v" 0 hello3hello3hello3 hello4hello4hello4hello4 //====================================================================== @@ -626,7 +682,7 @@ hello4hello4hello4hello4 -`line 389 "t/t_preproc.v" 0 +`line 438 "t/t_preproc.v" 0 `line 1 "t/t_preproc_inc4.vh" 1 // DESCRIPTION: Verilog::Preproc: Example source code `line 2 "t/t_preproc_inc4.vh" 0 @@ -638,9 +694,9 @@ hello4hello4hello4hello4 `line 8 "t/t_preproc_inc4.vh" 2 -`line 389 "t/t_preproc.v" 0 +`line 438 "t/t_preproc.v" 0 -`line 390 "t/t_preproc.v" 0 +`line 439 "t/t_preproc.v" 0 //====================================================================== // Defines doing defines @@ -650,28 +706,28 @@ hello4hello4hello4hello4 -`line 398 "t/t_preproc.v" 0 +`line 447 "t/t_preproc.v" 0 -Line_Preproc_Check 402 +Line_Preproc_Check 451 //====================================================================== // Quoted multiline - track line numbers, and ensure \\n gets propagated -Line_Preproc_Check 408 +Line_Preproc_Check 457 "FOO \ BAR " "arg_line1 \ arg_line2" "FOO \ BAR " -`line 411 "t/t_preproc.v" 0 -Line_Preproc_Check 411 +`line 460 "t/t_preproc.v" 0 +Line_Preproc_Check 460 //====================================================================== // bug283 -`line 415 "t/t_preproc.v" 0 +`line 464 "t/t_preproc.v" 0 @@ -682,14 +738,14 @@ abc -`line 425 "t/t_preproc.v" 0 +`line 474 "t/t_preproc.v" 0 EXP: sonet_frame sonet_frame -`line 431 "t/t_preproc.v" 0 +`line 480 "t/t_preproc.v" 0 EXP: sonet_frame @@ -700,7 +756,7 @@ sonet_frame EXP: sonet_frame sonet_frame -`line 441 "t/t_preproc.v" 0 +`line 490 "t/t_preproc.v" 0 // The existance of non-existance of a base define can make a difference @@ -708,13 +764,13 @@ EXP: module zzz ; endmodule module zzz ; endmodule module zzz ; endmodule -`line 448 "t/t_preproc.v" 0 +`line 497 "t/t_preproc.v" 0 EXP: module a_b ; endmodule module a_b ; endmodule module a_b ; endmodule -`line 453 "t/t_preproc.v" 0 +`line 502 "t/t_preproc.v" 0 //====================================================================== // bug311 integer/*NEED_SPACE*/ foo; @@ -728,7 +784,7 @@ module t; initial begin : \`LEX_CAT(a[0],_assignment) -`line 465 "t/t_preproc.v" 0 +`line 514 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`LEX_CAT(a[0],_assignment) "); end //----- // SHOULD(simulator-dependant): Backslash doesn't prevent arguments from @@ -737,7 +793,7 @@ module t; initial begin : \a[0]_assignment_a[1] -`line 472 "t/t_preproc.v" 0 +`line 521 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\a[0]_assignment_a[1] "); end //----- @@ -753,7 +809,7 @@ module t; // Similar to above; \ does not allow expansion after substitution initial begin : \`CAT(ff,bb) -`line 486 "t/t_preproc.v" 0 +`line 535 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`CAT(ff,bb) "); end //----- @@ -761,7 +817,7 @@ module t; // MUST: Unknown macro with backslash escape stays as escaped symbol name initial begin : \`zzz -`line 492 "t/t_preproc.v" 0 +`line 541 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\`zzz "); end //----- @@ -770,11 +826,11 @@ module t; // SHOULD(simulator-dependant): Known macro with backslash escape expands initial begin : \`FOO -`line 499 "t/t_preproc.v" 0 +`line 548 "t/t_preproc.v" 0 $write("GOT%%m='%m' OTHER_EXP='%s'\n OUR_EXP='%s'", "t.bar ","t.\\`FOO "); end // SHOULD(simulator-dependant): Prefix breaks the above initial begin : \xx`FOO -`line 501 "t/t_preproc.v" 0 +`line 550 "t/t_preproc.v" 0 $write("GOT%%m='%m' EXP='%s'\n", "t.\\xx`FOO "); end //----- @@ -807,27 +863,27 @@ module t; initial -`line 532 "t/t_preproc.v" 0 +`line 581 "t/t_preproc.v" 0 $display("%s%s","a1","b2c3\n"); endmodule -`line 535 "t/t_preproc.v" 0 +`line 584 "t/t_preproc.v" 0 //====================================================================== //bug1225 -`line 538 "t/t_preproc.v" 0 +`line 587 "t/t_preproc.v" 0 $display("RAM0"); $display("CPU"); -`line 543 "t/t_preproc.v" 0 +`line 592 "t/t_preproc.v" 0 -`line 548 "t/t_preproc.v" 0 +`line 597 "t/t_preproc.v" 0 XXE_FAMILY = XXE_ @@ -835,7 +891,7 @@ XXE_FAMILY = XXE_ $display("XXE_ is defined"); -`line 555 "t/t_preproc.v" 0 +`line 604 "t/t_preproc.v" 0 XYE_FAMILY = XYE_ @@ -843,7 +899,7 @@ XYE_FAMILY = XYE_ $display("XYE_ is defined"); -`line 562 "t/t_preproc.v" 0 +`line 611 "t/t_preproc.v" 0 XXS_FAMILY = XXS_some @@ -851,7 +907,7 @@ XXS_FAMILY = XXS_some $display("XXS_some is defined"); -`line 569 "t/t_preproc.v" 0 +`line 618 "t/t_preproc.v" 0 XYS_FAMILY = XYS_foo @@ -859,10 +915,10 @@ XYS_FAMILY = XYS_foo $display("XYS_foo is defined"); -`line 576 "t/t_preproc.v" 0 +`line 625 "t/t_preproc.v" 0 //==== -`line 578 "t/t_preproc.v" 0 +`line 627 "t/t_preproc.v" 0 @@ -871,7 +927,7 @@ XYS_FAMILY = XYS_foo -`line 586 "t/t_preproc.v" 0 +`line 635 "t/t_preproc.v" 0 @@ -879,7 +935,7 @@ XYS_FAMILY = XYS_foo -`line 593 "t/t_preproc.v" 0 +`line 642 "t/t_preproc.v" 0 @@ -887,7 +943,7 @@ XYS_FAMILY = XYS_foo -`line 600 "t/t_preproc.v" 0 +`line 649 "t/t_preproc.v" 0 @@ -895,26 +951,26 @@ XYS_FAMILY = XYS_foo -`line 607 "t/t_preproc.v" 0 +`line 656 "t/t_preproc.v" 0 -`line 609 "t/t_preproc.v" 0 +`line 658 "t/t_preproc.v" 0 // NEVER -`line 611 "t/t_preproc.v" 0 +`line 660 "t/t_preproc.v" 0 //bug1227 (.mySig (myInterface.pa5), -`line 615 "t/t_preproc.v" 0 +`line 664 "t/t_preproc.v" 0 //====================================================================== // Stringify bug -`line 618 "t/t_preproc.v" 0 +`line 667 "t/t_preproc.v" 0 `dbg_hdl(UVM_LOW, ("Functional coverage enabled: paramgrp")); -`line 621 "t/t_preproc.v" 0 +`line 670 "t/t_preproc.v" 0 @@ -923,28 +979,28 @@ XYS_FAMILY = XYS_foo -`line 629 "t/t_preproc.v" 0 +`line 678 "t/t_preproc.v" 0 module pcc2_cfg; generate -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 covergroup a @(posedge b); -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 c: coverpoint d iff ((c) === 1'b1); endgroup -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 a u_a; -`line 631 "t/t_preproc.v" 0 +`line 680 "t/t_preproc.v" 0 initial do begin $display ("DEBUG : %s [%m]", $sformatf ("Functional coverage enabled: u_a")); end while(0); endgenerate endmodule -`line 635 "t/t_preproc.v" 0 +`line 684 "t/t_preproc.v" 0 //====================================================================== // Verilog-Perl bug1668 "`NOT_DEFINED_STR" -`line 640 "t/t_preproc.v" 0 +`line 689 "t/t_preproc.v" 0 //====================================================================== // IEEE mandated predefines // undefineall should have no effect on these @@ -967,4 +1023,4 @@ predef 2 2 // After `undefineall above, for testing --dump-defines -`line 662 "t/t_preproc.v" 2 +`line 711 "t/t_preproc.v" 2 diff --git a/test_regress/t/t_reloop_cam.pl b/test_regress/t/t_reloop_cam.pl index e6d8da916..7046308bc 100755 --- a/test_regress/t/t_reloop_cam.pl +++ b/test_regress/t/t_reloop_cam.pl @@ -12,6 +12,7 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["-unroll-count 1024", + "--expand-limit 1024", $Self->wno_unopthreads_for_few_cores(), "--stats"], ); diff --git a/test_regress/t/t_reloop_offset.out b/test_regress/t/t_reloop_offset.out new file mode 100644 index 000000000..bc7054287 --- /dev/null +++ b/test_regress/t/t_reloop_offset.out @@ -0,0 +1,17 @@ +shift down 1 +oarray[63] is 0 +oarray[62] is 63 +oarray[61] is 62 +oarray[32] is 33 +oarray[ 2] is 3 +oarray[ 1] is 2 +oarray[ 0] is 1 +shift up 2 +oarray[63] is 61 +oarray[62] is 60 +oarray[61] is 59 +oarray[32] is 30 +oarray[ 2] is 0 +oarray[ 1] is 2 +oarray[ 0] is 1 +*-* All Finished *-* diff --git a/test_regress/t/t_reloop_offset.pl b/test_regress/t/t_reloop_offset.pl new file mode 100755 index 000000000..02f1f01fc --- /dev/null +++ b/test_regress/t/t_reloop_offset.pl @@ -0,0 +1,33 @@ +#!/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 => ["-unroll-count 1024", + $Self->wno_unopthreads_for_few_cores(), + "--stats"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, Reloop iterations\s+(\d+)/i, + 125); + file_grep($Self->{stats}, qr/Optimizations, Reloops\s+(\d+)/i, + 2); +} + +ok(1); +1; diff --git a/test_regress/t/t_reloop_offset.v b/test_regress/t/t_reloop_offset.v new file mode 100755 index 000000000..b4bfc4198 --- /dev/null +++ b/test_regress/t/t_reloop_offset.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, 2020 by Geza Lore. +// SPDX-License-Identifier: CC0-1.0 + +`define show(x) $display("oarray[%2d] is %2d", x, oarray[x]) + +module t (/*AUTOARG*/); + + int iarray [63:0]; + int oarray [63:0]; + + initial begin + for (int i = 0; i < 64 ; i = i + 1) begin + iarray[i] = i; + oarray[i] = 0; + end + + for (int i = 0; i < 63; i = i + 1) begin + oarray[i] = iarray[i + 1]; + end + + $display("shift down 1"); + `show(63); + `show(62); + `show(61); + `show(32); + `show(2); + `show(1); + `show(0); + + for (int i = 63; i >= 2 ; i = i - 1) begin + oarray[i] = iarray[i - 2]; + end + + $display("shift up 2"); + `show(63); + `show(62); + `show(61); + `show(32); + `show(2); + `show(1); + `show(0); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_reloop_offset_lim_63.pl b/test_regress/t/t_reloop_offset_lim_63.pl new file mode 100755 index 000000000..06d25c7b3 --- /dev/null +++ b/test_regress/t/t_reloop_offset_lim_63.pl @@ -0,0 +1,37 @@ +#!/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); + +top_filename("t/t_reloop_offset.v"); +golden_filename("t/t_reloop_offset.out"); + +compile( + verilator_flags2 => ["-unroll-count 1024", + $Self->wno_unopthreads_for_few_cores(), + "--reloop-limit 63", + "--stats"], + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +if ($Self->{vlt}) { + # Note, with vltmt this might be split differently, so only checking vlt + file_grep($Self->{stats}, qr/Optimizations, Reloop iterations\s+(\d+)/i, + 63); + file_grep($Self->{stats}, qr/Optimizations, Reloops\s+(\d+)/i, + 1); +} + +ok(1); +1; diff --git a/test_regress/t/t_sys_file_basic_mcd.out b/test_regress/t/t_sys_file_basic_mcd.out index bac06f7e9..636fdaca3 100644 --- a/test_regress/t/t_sys_file_basic_mcd.out +++ b/test_regress/t/t_sys_file_basic_mcd.out @@ -1,2 +1,3 @@ Sean Connery was the best Bond. +To file and to stdout *-* All Finished *-* diff --git a/test_regress/t/t_sys_file_basic_mcd.pl b/test_regress/t/t_sys_file_basic_mcd.pl index 106810fa0..e77ffbc08 100755 --- a/test_regress/t/t_sys_file_basic_mcd.pl +++ b/test_regress/t/t_sys_file_basic_mcd.pl @@ -24,6 +24,8 @@ files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test2_1.dat", "$Self->{t_dir}/t_sys_file_basic_mcd_test2_1.dat"); files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test2_2.dat", "$Self->{t_dir}/t_sys_file_basic_mcd_test2_2.dat"); +files_identical("$Self->{obj_dir}/t_sys_file_basic_mcd_test5.dat", + "$Self->{t_dir}/t_sys_file_basic_mcd_test5.dat"); ok(1); 1; diff --git a/test_regress/t/t_sys_file_basic_mcd.v b/test_regress/t/t_sys_file_basic_mcd.v index 16742829a..54d0aba21 100644 --- a/test_regress/t/t_sys_file_basic_mcd.v +++ b/test_regress/t/t_sys_file_basic_mcd.v @@ -30,7 +30,7 @@ module t; if (fd_fail != 0) fail("Able to allocate MCD descriptor when fully utilized."); // Return descriptor back to pool - fd_close = fd[0]; + fd_close = fd[0]; $fclose(fd_close); // Re-attempt MCD allocation; should pass at this point. fd_success = $fopen($sformatf("%s/yet_another_file.dat", `STR(`TEST_OBJ_DIR))); @@ -76,12 +76,21 @@ module t; int fd; // Wide filename fd = $fopen({`STR(`TEST_OBJ_DIR), - "some_very_large_filename_that_no_one_would_ever_use_", + "/some_very_large_filename_that_no_one_would_ever_use_", "except_to_purposefully_break_my_beautiful_code.dat"}); if (fd == 0) fail("Long filename could not be opened."); $fclose(fd); end endtask + task automatic test5; begin + 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 + initial begin // Test1: Validate file descriptor region. @@ -96,6 +105,9 @@ module t; // Test4: Validate filename lengths test4; + // Test5: OR with stdout + test5; + $write("*-* All Finished *-*\n"); $finish(0); // Test arguments to finish diff --git a/test_regress/t/t_sys_file_basic_mcd_test5.dat b/test_regress/t/t_sys_file_basic_mcd_test5.dat new file mode 100644 index 000000000..a623ecae3 --- /dev/null +++ b/test_regress/t/t_sys_file_basic_mcd_test5.dat @@ -0,0 +1 @@ +To file and to stdout diff --git a/test_regress/t/t_time_vpi.v b/test_regress/t/t_time_vpi.v index 84496b256..f1178d444 100644 --- a/test_regress/t/t_time_vpi.v +++ b/test_regress/t/t_time_vpi.v @@ -18,6 +18,7 @@ module t (/*AUTOARG*/ // verilator lint_off REALCVT time digits = 5432109876.543210ns; // Will round to time units realtime rdigits = 5432109876.543210ns; // Will round to time precision + time high_acc = 64'd12345678901234567890; // Would lose accuracy if calculated in double // verilator lint_on REALCVT always @ (posedge clk) begin @@ -31,10 +32,12 @@ module t (/*AUTOARG*/ $write("[%0t] time%%0d=%0d 123%%0t=%0t\n", $time, $time, 123); $write(" dig%%0t=%0t dig%%0d=%0d\n", digits, digits); $write(" rdig%%0t=%0t rdig%%0f=%0f\n", rdigits, rdigits); + $write(" acc%%0t=%0t acc%%0d=%0d\n", high_acc, high_acc); $timeformat(-9, 6, "ns", 16); $write("[%0t] time%%0d=%0d 123%%0t=%0t\n", $time, $time, 123); $write(" dig%%0t=%0t dig%%0d=%0d\n", digits, digits); $write(" rdig%%0t=%0t rdig%%0f=%0f\n", rdigits, rdigits); + $write(" acc%%0t=%0t acc%%0d=%0d\n", high_acc, high_acc); $write("[%0t] stime%%0t=%0t stime%%0d=%0d stime%%0f=%0f\n", $time, $stime, $stime, $stime); // verilator lint_off REALCVT diff --git a/test_regress/t/t_time_vpi_100s10ms.out b/test_regress/t/t_time_vpi_100s10ms.out index 73db352ca..8a0428fea 100644 --- a/test_regress/t/t_time_vpi_100s10ms.out +++ b/test_regress/t/t_time_vpi_100s10ms.out @@ -3,11 +3,13 @@ Time scale of t is 100s / 10ms [100000000] time%0d=10000 123%0t=1230000 dig%0t=0 dig%0d=0 rdig%0t=543 rdig%0f=0.054321 -[0.000000ns] time%0d=10000 123%0t=12300000000000.000000ns + acc%0t=123456789012345678900000 acc%0d=12345678901234567890 +[1000000000000000.000000ns] time%0d=10000 123%0t=12300000000000.000000ns dig%0t=0.000000ns dig%0d=0 rdig%0t=5432109876.543210ns rdig%0f=0.054321 -[0.000000ns] stime%0t=0.000000ns stime%0d=10000 stime%0f=10000.000000 -[0.000000ns] rtime%0t=0.000000ns rtime%0d=10000 rtime%0f=10000.000000 + acc%0t=1234567890123456789000000000000.000000ns acc%0d=12345678901234567890 +[1000000000000000.000000ns] stime%0t=1000000000000000.000000ns stime%0d=10000 stime%0f=10000.000000 +[1000000000000000.000000ns] rtime%0t=1000000000000000.000000ns rtime%0d=10000 rtime%0f=10000.000000 global vpiSimTime = 0,100000000 vpiScaledRealTime = 1e+08 global vpiTimeUnit = -2 vpiTimePrecision = -2 top.t vpiSimTime = 0,100000000 vpiScaledRealTime = 10000 diff --git a/test_regress/t/t_time_vpi_10ms10ns.out b/test_regress/t/t_time_vpi_10ms10ns.out index a561b40c3..b09a31d11 100644 --- a/test_regress/t/t_time_vpi_10ms10ns.out +++ b/test_regress/t/t_time_vpi_10ms10ns.out @@ -2,10 +2,12 @@ Time scale of t is 10ms / 10ns [60000000] time%0d=60 123%0t=123000000 dig%0t=543000000 dig%0d=543 - rdig%0t=543210987 rdig%0f=543.210988 + rdig%0t=543210988 rdig%0f=543.210988 + acc%0t=12345678901234567890000000 acc%0d=12345678901234567890 [600000000.000000ns] time%0d=60 123%0t=1230000000.000000ns dig%0t=5430000000.000000ns dig%0d=543 rdig%0t=5432109876.543210ns rdig%0f=543.210988 + acc%0t=123456789012345678900000000.000000ns acc%0d=12345678901234567890 [600000000.000000ns] stime%0t=600000000.000000ns stime%0d=60 stime%0f=60.000000 [600000000.000000ns] rtime%0t=600000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000000 vpiScaledRealTime = 6e+07 diff --git a/test_regress/t/t_time_vpi_1fs1fs.out b/test_regress/t/t_time_vpi_1fs1fs.out index 680d87168..a353d9cea 100644 --- a/test_regress/t/t_time_vpi_1fs1fs.out +++ b/test_regress/t/t_time_vpi_1fs1fs.out @@ -3,9 +3,11 @@ Time scale of t is 1fs / 1fs [60] time%0d=60 123%0t=123 dig%0t=5432109876543210 dig%0d=5432109876543210 rdig%0t=5432109876543210 rdig%0f=5432109876543210.000000 + acc%0t=12345678901234567890 acc%0d=12345678901234567890 [0.000060ns] time%0d=60 123%0t=0.000123ns dig%0t=5432109876.543210ns dig%0d=5432109876543210 rdig%0t=5432109876.543210ns rdig%0f=5432109876543210.000000 + acc%0t=12345678901234.567890ns acc%0d=12345678901234567890 [0.000060ns] stime%0t=0.000060ns stime%0d=60 stime%0f=60.000000 [0.000060ns] rtime%0t=0.000060ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1ms10ns.out b/test_regress/t/t_time_vpi_1ms10ns.out index 90ce5a0ed..1276f8d4c 100644 --- a/test_regress/t/t_time_vpi_1ms10ns.out +++ b/test_regress/t/t_time_vpi_1ms10ns.out @@ -2,10 +2,12 @@ Time scale of t is 1ms / 10ns [6000000] time%0d=60 123%0t=12300000 dig%0t=543200000 dig%0d=5432 - rdig%0t=543210987 rdig%0f=5432.109877 + rdig%0t=543210988 rdig%0f=5432.109877 + acc%0t=1234567890123456789000000 acc%0d=12345678901234567890 [60000000.000000ns] time%0d=60 123%0t=123000000.000000ns dig%0t=5432000000.000000ns dig%0d=5432 rdig%0t=5432109876.543210ns rdig%0f=5432.109877 + acc%0t=12345678901234567890000000.000000ns acc%0d=12345678901234567890 [60000000.000000ns] stime%0t=60000000.000000ns stime%0d=60 stime%0f=60.000000 [60000000.000000ns] rtime%0t=60000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,6000000 vpiScaledRealTime = 6e+06 diff --git a/test_regress/t/t_time_vpi_1ns1ns.out b/test_regress/t/t_time_vpi_1ns1ns.out index b6dad7274..b9e6d3ed1 100644 --- a/test_regress/t/t_time_vpi_1ns1ns.out +++ b/test_regress/t/t_time_vpi_1ns1ns.out @@ -2,10 +2,12 @@ Time scale of t is 1ns / 1ns [60] time%0d=60 123%0t=123 dig%0t=5432109877 dig%0d=5432109877 - rdig%0t=5432109876 rdig%0f=5432109876.543210 + rdig%0t=5432109877 rdig%0f=5432109876.543210 + acc%0t=12345678901234567890 acc%0d=12345678901234567890 [60.000000ns] time%0d=60 123%0t=123.000000ns dig%0t=5432109877.000000ns dig%0d=5432109877 rdig%0t=5432109876.543210ns rdig%0f=5432109876.543210 + acc%0t=12345678901234567890.000000ns acc%0d=12345678901234567890 [60.000000ns] stime%0t=60.000000ns stime%0d=60 stime%0f=60.000000 [60.000000ns] rtime%0t=60.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1ps1fs.out b/test_regress/t/t_time_vpi_1ps1fs.out index c4935bc16..3a391485d 100644 --- a/test_regress/t/t_time_vpi_1ps1fs.out +++ b/test_regress/t/t_time_vpi_1ps1fs.out @@ -2,12 +2,14 @@ Time scale of t is 1ps / 1fs [60000] time%0d=60 123%0t=123000 dig%0t=5432109876543000 dig%0d=5432109876543 - rdig%0t=5432109876543209 rdig%0f=5432109876543.209961 + rdig%0t=5432109876543210 rdig%0f=5432109876543.209961 + acc%0t=12345678901234567890000 acc%0d=12345678901234567890 [0.060000ns] time%0d=60 123%0t=0.123000ns dig%0t=5432109876.543000ns dig%0d=5432109876543 - rdig%0t=5432109876.543209ns rdig%0f=5432109876543.209961 + rdig%0t=5432109876.543210ns rdig%0f=5432109876543.209961 + acc%0t=12345678901234567.890000ns acc%0d=12345678901234567890 [0.060000ns] stime%0t=0.060000ns stime%0d=60 stime%0f=60.000000 -[0.060000ns] rtime%0t=0.059999ns rtime%0d=60 rtime%0f=60.000000 +[0.060000ns] rtime%0t=0.060000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 global vpiTimeUnit = -12 vpiTimePrecision = -15 top.t vpiSimTime = 0,60000 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_time_vpi_1s10ns.out b/test_regress/t/t_time_vpi_1s10ns.out index ba22c32bb..b950e9176 100644 --- a/test_regress/t/t_time_vpi_1s10ns.out +++ b/test_regress/t/t_time_vpi_1s10ns.out @@ -2,10 +2,12 @@ Time scale of t is 1s / 10ns [6000000000] time%0d=60 123%0t=12300000000 dig%0t=500000000 dig%0d=5 - rdig%0t=543210987 rdig%0f=5.432110 + rdig%0t=543210988 rdig%0f=5.432110 + acc%0t=1234567890123456789000000000 acc%0d=12345678901234567890 [60000000000.000000ns] time%0d=60 123%0t=123000000000.000000ns dig%0t=5000000000.000000ns dig%0d=5 rdig%0t=5432109876.543210ns rdig%0f=5.432110 + acc%0t=12345678901234567890000000000.000000ns acc%0d=12345678901234567890 [60000000000.000000ns] stime%0t=60000000000.000000ns stime%0d=60 stime%0f=60.000000 [60000000000.000000ns] rtime%0t=60000000000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 1,1705032704 vpiScaledRealTime = 6e+09 diff --git a/test_regress/t/t_time_vpi_1us1ns.out b/test_regress/t/t_time_vpi_1us1ns.out index 182c19aa7..59d7e4ea8 100644 --- a/test_regress/t/t_time_vpi_1us1ns.out +++ b/test_regress/t/t_time_vpi_1us1ns.out @@ -2,12 +2,14 @@ Time scale of t is 1us / 1ns [60000] time%0d=60 123%0t=123000 dig%0t=5432110000 dig%0d=5432110 - rdig%0t=5432109876 rdig%0f=5432109.876543 + rdig%0t=5432109877 rdig%0f=5432109.876543 + acc%0t=12345678901234567890000 acc%0d=12345678901234567890 [60000.000000ns] time%0d=60 123%0t=123000.000000ns dig%0t=5432110000.000000ns dig%0d=5432110 - rdig%0t=5432109876.543209ns rdig%0f=5432109.876543 + rdig%0t=5432109876.543210ns rdig%0f=5432109.876543 + acc%0t=12345678901234567890000.000000ns acc%0d=12345678901234567890 [60000.000000ns] stime%0t=60000.000000ns stime%0d=60 stime%0f=60.000000 -[60000.000000ns] rtime%0t=59999.999999ns rtime%0d=60 rtime%0f=60.000000 +[60000.000000ns] rtime%0t=60000.000000ns rtime%0d=60 rtime%0f=60.000000 global vpiSimTime = 0,60000 vpiScaledRealTime = 60000 global vpiTimeUnit = -6 vpiTimePrecision = -9 top.t vpiSimTime = 0,60000 vpiScaledRealTime = 60 diff --git a/test_regress/t/t_trace_fst_cmake.out b/test_regress/t/t_trace_fst_cmake.out new file mode 100644 index 000000000..dde4f07e0 --- /dev/null +++ b/test_regress/t/t_trace_fst_cmake.out @@ -0,0 +1,1028 @@ +$date + Sun Apr 19 04:15:36 2020 + +$end +$version + fstWriter +$end +$timescale + 1ps +$end +$scope module top $end +$var wire 1 ! clk $end +$var wire 5 " state $end +$scope module t $end +$var wire 1 ! clk $end +$var int 32 # cyc $end +$var logic 1 $ rstn $end +$var wire 5 " state $end +$var real_parameter 64 % fst_gparam_real $end +$var real_parameter 64 & fst_lparam_real $end +$var real 64 % fst_real $end +$var integer 32 ' fst_integer $end +$var bit 1 ( fst_bit $end +$var logic 1 ) fst_logic $end +$var int 32 * fst_int $end +$var shortint 16 + fst_shortint $end +$var longint 64 , fst_longint $end +$var byte 8 - fst_byte $end +$var parameter 32 . fst_parameter $end +$var parameter 32 / fst_lparam $end +$var supply0 1 0 fst_supply0 $end +$var supply1 1 1 fst_supply1 $end +$var tri0 1 2 fst_tri0 $end +$var tri1 1 3 fst_tri1 $end +$var tri 1 4 fst_tri $end +$var wire 1 5 fst_wire $end +$scope module test $end +$var wire 1 ! clk $end +$var wire 1 $ rstn $end +$var wire 5 " state $end +$var logic 5 6 state_w $end +$var logic 5 7 state_array(0) $end +$var logic 5 8 state_array(1) $end +$var logic 5 9 state_array(2) $end +$scope module unnamedblk2 $end +$var int 32 : i $end +$upscope $end +$scope module unnamedblk1 $end +$var int 32 ; i $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$enddefinitions $end +$dumpvars +0! +b00000 " +b00000000000000000000000000000000 # +0$ +r1.23 % +r4.56 & +b00000000000000000000000000000000 ' +0( +0) +b00000000000000000000000000000000 * +b0000000000000000 + +b0000000000000000000000000000000000000000000000000000000000000000 , +b00000000 - +b00000000000000000000000001111011 . +b00000000000000000000000111001000 / +00 +11 +02 +13 +04 +05 +b00000 6 +b00000 7 +b00000 8 +b00000 9 +b00000000000000000000000000000000 : +b00000000000000000000000000000000 ; +#10 +b00000000000000000000000000000011 ; +b00001 9 +b00001 8 +b00001 7 +b10100 6 +b00000000000000000000000000000001 # +b00001 " +1! +#15 +0! +#20 +1! +b00000000000000000000000000000010 # +#25 +0! +#30 +1! +b00000000000000000000000000000011 # +#35 +0! +#40 +1! +b00000000000000000000000000000100 # +#45 +0! +#50 +1! +b00000000000000000000000000000101 # +#55 +0! +#60 +1! +b00000000000000000000000000000110 # +#65 +0! +#70 +1! +b00000000000000000000000000000111 # +#75 +0! +#80 +1! +b00000000000000000000000000001000 # +#85 +0! +#90 +1! +b00000000000000000000000000001001 # +#95 +0! +#100 +1! +b00000000000000000000000000001010 # +#105 +0! +#110 +1! +b00000000000000000000000000001011 # +1$ +#115 +0! +#120 +1! +b00000000000000000000000000001100 # +b01010 6 +b10100 9 +b00000000000000000000000000000010 : +#125 +0! +#130 +1! +b01010 9 +b00101 6 +b00000000000000000000000000001101 # +b10100 8 +#135 +0! +#140 +1! +b01010 8 +b00000000000000000000000000001110 # +b10110 6 +b00101 9 +b10100 " +b10100 7 +#145 +0! +#150 +1! +b01010 7 +b01010 " +b10110 9 +b01011 6 +b00000000000000000000000000001111 # +b00101 8 +#155 +0! +#160 +1! +b10110 8 +b00000000000000000000000000010000 # +b10001 6 +b01011 9 +b00101 " +b00101 7 +#165 +0! +#170 +1! +b10110 7 +b10110 " +b10001 9 +b11100 6 +b00000000000000000000000000010001 # +b01011 8 +#175 +0! +#180 +1! +b10001 8 +b00000000000000000000000000010010 # +b01110 6 +b11100 9 +b01011 " +b01011 7 +#185 +0! +#190 +1! +b10001 7 +b10001 " +b01110 9 +b00111 6 +b00000000000000000000000000010011 # +b11100 8 +#195 +0! +#200 +1! +b01110 8 +b00000000000000000000000000010100 # +b10111 6 +b00111 9 +b11100 " +b11100 7 +#205 +0! +#210 +1! +b01110 7 +b01110 " +b10111 9 +b11111 6 +b00000000000000000000000000010101 # +b00111 8 +#215 +0! +#220 +1! +b10111 8 +b00000000000000000000000000010110 # +b11011 6 +b11111 9 +b00111 " +b00111 7 +#225 +0! +#230 +1! +b10111 7 +b10111 " +b11011 9 +b11001 6 +b00000000000000000000000000010111 # +b11111 8 +#235 +0! +#240 +1! +b11011 8 +b00000000000000000000000000011000 # +b11000 6 +b11001 9 +b11111 " +b11111 7 +#245 +0! +#250 +1! +b11011 7 +b11011 " +b11000 9 +b01100 6 +b00000000000000000000000000011001 # +b11001 8 +#255 +0! +#260 +1! +b11000 8 +b00000000000000000000000000011010 # +b00110 6 +b01100 9 +b11001 " +b11001 7 +#265 +0! +#270 +1! +b11000 7 +b11000 " +b00110 9 +b00011 6 +b00000000000000000000000000011011 # +b01100 8 +#275 +0! +#280 +1! +b00110 8 +b00000000000000000000000000011100 # +b10101 6 +b00011 9 +b01100 " +b01100 7 +#285 +0! +#290 +1! +b00110 7 +b00110 " +b10101 9 +b11110 6 +b00000000000000000000000000011101 # +b00011 8 +#295 +0! +#300 +1! +b10101 8 +b00000000000000000000000000011110 # +b01111 6 +b11110 9 +b00011 " +b00011 7 +#305 +0! +#310 +1! +b10101 7 +b10101 " +b01111 9 +b10011 6 +b00000000000000000000000000011111 # +b11110 8 +#315 +0! +#320 +1! +b01111 8 +b00000000000000000000000000100000 # +b11101 6 +b10011 9 +b11110 " +b11110 7 +#325 +0! +#330 +1! +b01111 7 +b01111 " +b11101 9 +b11010 6 +b00000000000000000000000000100001 # +b10011 8 +#335 +0! +#340 +1! +b11101 8 +b00000000000000000000000000100010 # +b01101 6 +b11010 9 +b10011 " +b10011 7 +#345 +0! +#350 +1! +b11101 7 +b11101 " +b01101 9 +b10010 6 +b00000000000000000000000000100011 # +b11010 8 +#355 +0! +#360 +1! +b01101 8 +b00000000000000000000000000100100 # +b01001 6 +b10010 9 +b11010 " +b11010 7 +#365 +0! +#370 +1! +b01101 7 +b01101 " +b01001 9 +b10000 6 +b00000000000000000000000000100101 # +b10010 8 +#375 +0! +#380 +1! +b01001 8 +b00000000000000000000000000100110 # +b01000 6 +b10000 9 +b10010 " +b10010 7 +#385 +0! +#390 +1! +b01001 7 +b01001 " +b01000 9 +b00100 6 +b00000000000000000000000000100111 # +b10000 8 +#395 +0! +#400 +1! +b01000 8 +b00000000000000000000000000101000 # +b00010 6 +b00100 9 +b10000 " +b10000 7 +#405 +0! +#410 +1! +b01000 7 +b01000 " +b00010 9 +b00001 6 +b00000000000000000000000000101001 # +b00100 8 +#415 +0! +#420 +1! +b00010 8 +b00000000000000000000000000101010 # +b10100 6 +b00001 9 +b00100 " +b00100 7 +#425 +0! +#430 +1! +b00010 7 +b00010 " +b10100 9 +b01010 6 +b00000000000000000000000000101011 # +b00001 8 +#435 +0! +#440 +1! +b10100 8 +b00000000000000000000000000101100 # +b00101 6 +b01010 9 +b00001 " +b00001 7 +#445 +0! +#450 +1! +b10100 7 +b10100 " +b00101 9 +b10110 6 +b00000000000000000000000000101101 # +b01010 8 +#455 +0! +#460 +1! +b00101 8 +b00000000000000000000000000101110 # +b01011 6 +b10110 9 +b01010 " +b01010 7 +#465 +0! +#470 +1! +b00101 7 +b00101 " +b01011 9 +b10001 6 +b00000000000000000000000000101111 # +b10110 8 +#475 +0! +#480 +1! +b01011 8 +b00000000000000000000000000110000 # +b11100 6 +b10001 9 +b10110 " +b10110 7 +#485 +0! +#490 +1! +b01011 7 +b01011 " +b11100 9 +b01110 6 +b00000000000000000000000000110001 # +b10001 8 +#495 +0! +#500 +1! +b11100 8 +b00000000000000000000000000110010 # +b00111 6 +b01110 9 +b10001 " +b10001 7 +#505 +0! +#510 +1! +b11100 7 +b11100 " +b00111 9 +b10111 6 +b00000000000000000000000000110011 # +b01110 8 +#515 +0! +#520 +1! +b00111 8 +b00000000000000000000000000110100 # +b11111 6 +b10111 9 +b01110 " +b01110 7 +#525 +0! +#530 +1! +b00111 7 +b00111 " +b11111 9 +b11011 6 +b00000000000000000000000000110101 # +b10111 8 +#535 +0! +#540 +1! +b11111 8 +b00000000000000000000000000110110 # +b11001 6 +b11011 9 +b10111 " +b10111 7 +#545 +0! +#550 +1! +b11111 7 +b11111 " +b11001 9 +b11000 6 +b00000000000000000000000000110111 # +b11011 8 +#555 +0! +#560 +1! +b11001 8 +b00000000000000000000000000111000 # +b01100 6 +b11000 9 +b11011 " +b11011 7 +#565 +0! +#570 +1! +b11001 7 +b11001 " +b01100 9 +b00110 6 +b00000000000000000000000000111001 # +b11000 8 +#575 +0! +#580 +1! +b01100 8 +b00000000000000000000000000111010 # +b00011 6 +b00110 9 +b11000 " +b11000 7 +#585 +0! +#590 +1! +b01100 7 +b01100 " +b00011 9 +b10101 6 +b00000000000000000000000000111011 # +b00110 8 +#595 +0! +#600 +1! +b00011 8 +b00000000000000000000000000111100 # +b11110 6 +b10101 9 +b00110 " +b00110 7 +#605 +0! +#610 +1! +b00011 7 +b00011 " +b11110 9 +b01111 6 +b00000000000000000000000000111101 # +b10101 8 +#615 +0! +#620 +1! +b11110 8 +b00000000000000000000000000111110 # +b10011 6 +b01111 9 +b10101 " +b10101 7 +#625 +0! +#630 +1! +b11110 7 +b11110 " +b10011 9 +b11101 6 +b00000000000000000000000000111111 # +b01111 8 +#635 +0! +#640 +1! +b10011 8 +b00000000000000000000000001000000 # +b11010 6 +b11101 9 +b01111 " +b01111 7 +#645 +0! +#650 +1! +b10011 7 +b10011 " +b11010 9 +b01101 6 +b00000000000000000000000001000001 # +b11101 8 +#655 +0! +#660 +1! +b11010 8 +b00000000000000000000000001000010 # +b10010 6 +b01101 9 +b11101 " +b11101 7 +#665 +0! +#670 +1! +b11010 7 +b11010 " +b10010 9 +b01001 6 +b00000000000000000000000001000011 # +b01101 8 +#675 +0! +#680 +1! +b10010 8 +b00000000000000000000000001000100 # +b10000 6 +b01001 9 +b01101 " +b01101 7 +#685 +0! +#690 +1! +b10010 7 +b10010 " +b10000 9 +b01000 6 +b00000000000000000000000001000101 # +b01001 8 +#695 +0! +#700 +1! +b10000 8 +b00000000000000000000000001000110 # +b00100 6 +b01000 9 +b01001 " +b01001 7 +#705 +0! +#710 +1! +b10000 7 +b10000 " +b00100 9 +b00010 6 +b00000000000000000000000001000111 # +b01000 8 +#715 +0! +#720 +1! +b00100 8 +b00000000000000000000000001001000 # +b00001 6 +b00010 9 +b01000 " +b01000 7 +#725 +0! +#730 +1! +b00100 7 +b00100 " +b00001 9 +b10100 6 +b00000000000000000000000001001001 # +b00010 8 +#735 +0! +#740 +1! +b00001 8 +b00000000000000000000000001001010 # +b01010 6 +b10100 9 +b00010 " +b00010 7 +#745 +0! +#750 +1! +b00001 7 +b00001 " +b01010 9 +b00101 6 +b00000000000000000000000001001011 # +b10100 8 +#755 +0! +#760 +1! +b01010 8 +b00000000000000000000000001001100 # +b10110 6 +b00101 9 +b10100 " +b10100 7 +#765 +0! +#770 +1! +b01010 7 +b01010 " +b10110 9 +b01011 6 +b00000000000000000000000001001101 # +b00101 8 +#775 +0! +#780 +1! +b10110 8 +b00000000000000000000000001001110 # +b10001 6 +b01011 9 +b00101 " +b00101 7 +#785 +0! +#790 +1! +b10110 7 +b10110 " +b10001 9 +b11100 6 +b00000000000000000000000001001111 # +b01011 8 +#795 +0! +#800 +1! +b10001 8 +b00000000000000000000000001010000 # +b01110 6 +b11100 9 +b01011 " +b01011 7 +#805 +0! +#810 +1! +b10001 7 +b10001 " +b01110 9 +b00111 6 +b00000000000000000000000001010001 # +b11100 8 +#815 +0! +#820 +1! +b01110 8 +b00000000000000000000000001010010 # +b10111 6 +b00111 9 +b11100 " +b11100 7 +#825 +0! +#830 +1! +b01110 7 +b01110 " +b10111 9 +b11111 6 +b00000000000000000000000001010011 # +b00111 8 +#835 +0! +#840 +1! +b10111 8 +b00000000000000000000000001010100 # +b11011 6 +b11111 9 +b00111 " +b00111 7 +#845 +0! +#850 +1! +b10111 7 +b10111 " +b11011 9 +b11001 6 +b00000000000000000000000001010101 # +b11111 8 +#855 +0! +#860 +1! +b11011 8 +b00000000000000000000000001010110 # +b11000 6 +b11001 9 +b11111 " +b11111 7 +#865 +0! +#870 +1! +b11011 7 +b11011 " +b11000 9 +b01100 6 +b00000000000000000000000001010111 # +b11001 8 +#875 +0! +#880 +1! +b11000 8 +b00000000000000000000000001011000 # +b00110 6 +b01100 9 +b11001 " +b11001 7 +#885 +0! +#890 +1! +b11000 7 +b11000 " +b00110 9 +b00011 6 +b00000000000000000000000001011001 # +b01100 8 +#895 +0! +#900 +1! +b00110 8 +b00000000000000000000000001011010 # +b10101 6 +b00011 9 +b01100 " +b01100 7 +#905 +0! +#910 +1! +b00110 7 +b00110 " +b10101 9 +b11110 6 +b00000000000000000000000001011011 # +b00011 8 +#915 +0! +#920 +1! +b10101 8 +b00000000000000000000000001011100 # +b01111 6 +b11110 9 +b00011 " +b00011 7 +#925 +0! +#930 +1! +b10101 7 +b10101 " +b01111 9 +b10011 6 +b00000000000000000000000001011101 # +b11110 8 +#935 +0! +#940 +1! +b01111 8 +b00000000000000000000000001011110 # +b11101 6 +b10011 9 +b11110 " +b11110 7 +#945 +0! +#950 +1! +b01111 7 +b01111 " +b11101 9 +b11010 6 +b00000000000000000000000001011111 # +b10011 8 +#955 +0! +#960 +1! +b11101 8 +b00000000000000000000000001100000 # +b01101 6 +b11010 9 +b10011 " +b10011 7 +#965 +0! +#970 +1! +b11101 7 +b11101 " +b01101 9 +b10010 6 +b00000000000000000000000001100001 # +b11010 8 +#975 +0! +#980 +1! +b01101 8 +b00000000000000000000000001100010 # +b01001 6 +b10010 9 +b11010 " +b11010 7 +#985 +0! +#990 +1! +b01101 7 +b01101 " +b01001 9 +b10000 6 +b00000000000000000000000001100011 # +b10010 8 +#995 +0! +#1000 +1! +b01001 8 +b00000000000000000000000001100100 # +b01000 6 +b10000 9 +b10010 " +b10010 7 diff --git a/test_regress/t/t_trace_fst_cmake.pl b/test_regress/t/t_trace_fst_cmake.pl new file mode 100755 index 000000000..4a00d2fb6 --- /dev/null +++ b/test_regress/t/t_trace_fst_cmake.pl @@ -0,0 +1,27 @@ +#!/usr/bin/env perl +# 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 + +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } + +scenarios(vlt_all => 1); + +compile( + v_flags2 => ["--trace-fst"], + verilator_make_gmake => 0, + verilator_make_cmake => 1, +); + +execute( + check_finished => 1, +); + +fst_identical($Self->trace_filename, $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_trace_fst_cmake.v b/test_regress/t/t_trace_fst_cmake.v new file mode 100644 index 000000000..288ddadfc --- /dev/null +++ b/test_regress/t/t_trace_fst_cmake.v @@ -0,0 +1,99 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// Author: Yu-Sheng Lin johnjohnlys@media.ee.ntu.edu.tw +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Outputs + state, + // Inputs + clk + ); + + input clk; + + int cyc; + reg rstn; + output [4:0] state; + + parameter real fst_gparam_real = 1.23; + localparam real fst_lparam_real = 4.56; + real fst_real = 1.23; + integer fst_integer; + bit fst_bit; + logic fst_logic; + int fst_int; + shortint fst_shortint; + longint fst_longint; + byte fst_byte; + + parameter fst_parameter = 123; + localparam fst_lparam = 456; + supply0 fst_supply0; + supply1 fst_supply1; + tri0 fst_tri0; + tri1 fst_tri1; + tri fst_tri; + wire fst_wire; + + Test test (/*AUTOINST*/ + // Outputs + .state (state[4:0]), + // Inputs + .clk (clk), + .rstn (rstn)); + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc==0) begin + // Setup + rstn <= ~'1; + end + else if (cyc<10) begin + rstn <= ~'1; + end + else if (cyc<90) begin + rstn <= ~'0; + end + else if (cyc==99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + + +module Test ( + input clk, + input rstn, + output logic [4:0] state + ); + + logic [4:0] state_w; + logic [4:0] state_array [3]; + assign state = state_array[0]; + + always_comb begin + state_w[4] = state_array[2][0]; + state_w[3] = state_array[2][4]; + state_w[2] = state_array[2][3] ^ state_array[2][0]; + state_w[1] = state_array[2][2]; + state_w[0] = state_array[2][1]; + end + + always_ff @(posedge clk or negedge rstn) begin + if (!rstn) begin + for (int i = 0; i < 3; i++) + state_array[i] <= 'b1; + end + else begin + for (int i = 0; i < 2; i++) + state_array[i] <= state_array[i+1]; + state_array[2] <= state_w; + end + end + +endmodule diff --git a/test_regress/t/t_trace_fst_sc_cmake.out b/test_regress/t/t_trace_fst_sc_cmake.out new file mode 100644 index 000000000..3fe026e70 --- /dev/null +++ b/test_regress/t/t_trace_fst_sc_cmake.out @@ -0,0 +1,1824 @@ +$date + Thu Apr 1 14:28:55 2021 + +$end +$version + fstWriter +$end +$timescale + 1ps +$end +$scope module top $end +$scope module t $end +$var wire 1 ! clk $end +$var int 32 " cyc $end +$var logic 1 # rstn $end +$var real_parameter 64 $ fst_gparam_real $end +$var real_parameter 64 % fst_lparam_real $end +$var real 64 $ fst_real $end +$var integer 32 & fst_integer $end +$var bit 1 ' fst_bit $end +$var logic 1 ( fst_logic $end +$var int 32 ) fst_int $end +$var shortint 16 * fst_shortint $end +$var longint 64 + fst_longint $end +$var byte 8 , fst_byte $end +$var parameter 32 - fst_parameter $end +$var parameter 32 . fst_lparam $end +$var supply0 1 / fst_supply0 $end +$var supply1 1 0 fst_supply1 $end +$var tri0 1 1 fst_tri0 $end +$var tri1 1 2 fst_tri1 $end +$var tri 1 3 fst_tri $end +$var wire 1 4 fst_wire $end +$var logic 5 5 state $end +$scope module test $end +$var wire 1 ! clk $end +$var wire 1 # rstn $end +$var wire 5 5 state $end +$var logic 5 6 state_w $end +$var logic 5 7 state_array(0) $end +$var logic 5 8 state_array(1) $end +$var logic 5 9 state_array(2) $end +$scope module unnamedblk2 $end +$var int 32 : i $end +$upscope $end +$scope module unnamedblk1 $end +$var int 32 ; i $end +$upscope $end +$upscope $end +$upscope $end +$upscope $end +$enddefinitions $end +#0 +$dumpvars +b00000000000000000000000000000000 ; +b00000000000000000000000000000000 : +b00000 9 +b00000 8 +b00000 7 +b00000 6 +b00000 5 +04 +03 +12 +01 +10 +0/ +b00000000000000000000000111001000 . +b00000000000000000000000001111011 - +b00000000 , +b0000000000000000000000000000000000000000000000000000000000000000 + +b0000000000000000 * +b00000000000000000000000000000000 ) +0( +0' +b00000000000000000000000000000000 & +r4.56 % +r1.23 $ +0# +b00000000000000000000000000000000 " +0! +$end +#10 +1! +b00000000000000000000000000000001 " +b00001 5 +b10100 6 +b00001 7 +b00001 8 +b00001 9 +b00000000000000000000000000000011 ; +#11 +#12 +#13 +#14 +#15 +0! +#16 +#17 +#18 +#19 +#20 +1! +b00000000000000000000000000000010 " +#21 +#22 +#23 +#24 +#25 +0! +#26 +#27 +#28 +#29 +#30 +1! +b00000000000000000000000000000011 " +#31 +#32 +#33 +#34 +#35 +0! +#36 +#37 +#38 +#39 +#40 +1! +b00000000000000000000000000000100 " +#41 +#42 +#43 +#44 +#45 +0! +#46 +#47 +#48 +#49 +#50 +1! +b00000000000000000000000000000101 " +#51 +#52 +#53 +#54 +#55 +0! +#56 +#57 +#58 +#59 +#60 +1! +b00000000000000000000000000000110 " +#61 +#62 +#63 +#64 +#65 +0! +#66 +#67 +#68 +#69 +#70 +1! +b00000000000000000000000000000111 " +#71 +#72 +#73 +#74 +#75 +0! +#76 +#77 +#78 +#79 +#80 +1! +b00000000000000000000000000001000 " +#81 +#82 +#83 +#84 +#85 +0! +#86 +#87 +#88 +#89 +#90 +1! +b00000000000000000000000000001001 " +#91 +#92 +#93 +#94 +#95 +0! +#96 +#97 +#98 +#99 +#100 +1! +b00000000000000000000000000001010 " +#101 +#102 +#103 +#104 +#105 +0! +#106 +#107 +#108 +#109 +#110 +1! +b00000000000000000000000000001011 " +1# +#111 +#112 +#113 +#114 +#115 +0! +#116 +#117 +#118 +#119 +#120 +1! +b00000000000000000000000000001100 " +b10100 9 +b01010 6 +b00000000000000000000000000000010 : +#121 +#122 +#123 +#124 +#125 +0! +#126 +#127 +#128 +#129 +#130 +1! +b00101 6 +b01010 9 +b00000000000000000000000000001101 " +b10100 8 +#131 +#132 +#133 +#134 +#135 +0! +#136 +#137 +#138 +#139 +#140 +1! +b01010 8 +b00000000000000000000000000001110 " +b00101 9 +b10110 6 +b10100 7 +b10100 5 +#141 +#142 +#143 +#144 +#145 +0! +#146 +#147 +#148 +#149 +#150 +1! +b01010 5 +b01010 7 +b01011 6 +b10110 9 +b00000000000000000000000000001111 " +b00101 8 +#151 +#152 +#153 +#154 +#155 +0! +#156 +#157 +#158 +#159 +#160 +1! +b10110 8 +b00000000000000000000000000010000 " +b01011 9 +b10001 6 +b00101 7 +b00101 5 +#161 +#162 +#163 +#164 +#165 +0! +#166 +#167 +#168 +#169 +#170 +1! +b10110 5 +b10110 7 +b11100 6 +b10001 9 +b00000000000000000000000000010001 " +b01011 8 +#171 +#172 +#173 +#174 +#175 +0! +#176 +#177 +#178 +#179 +#180 +1! +b10001 8 +b00000000000000000000000000010010 " +b11100 9 +b01110 6 +b01011 7 +b01011 5 +#181 +#182 +#183 +#184 +#185 +0! +#186 +#187 +#188 +#189 +#190 +1! +b10001 5 +b10001 7 +b00111 6 +b01110 9 +b00000000000000000000000000010011 " +b11100 8 +#191 +#192 +#193 +#194 +#195 +0! +#196 +#197 +#198 +#199 +#200 +1! +b01110 8 +b00000000000000000000000000010100 " +b00111 9 +b10111 6 +b11100 7 +b11100 5 +#201 +#202 +#203 +#204 +#205 +0! +#206 +#207 +#208 +#209 +#210 +1! +b01110 5 +b01110 7 +b11111 6 +b10111 9 +b00000000000000000000000000010101 " +b00111 8 +#211 +#212 +#213 +#214 +#215 +0! +#216 +#217 +#218 +#219 +#220 +1! +b10111 8 +b00000000000000000000000000010110 " +b11111 9 +b11011 6 +b00111 7 +b00111 5 +#221 +#222 +#223 +#224 +#225 +0! +#226 +#227 +#228 +#229 +#230 +1! +b10111 5 +b10111 7 +b11001 6 +b11011 9 +b00000000000000000000000000010111 " +b11111 8 +#231 +#232 +#233 +#234 +#235 +0! +#236 +#237 +#238 +#239 +#240 +1! +b11011 8 +b00000000000000000000000000011000 " +b11001 9 +b11000 6 +b11111 7 +b11111 5 +#241 +#242 +#243 +#244 +#245 +0! +#246 +#247 +#248 +#249 +#250 +1! +b11011 5 +b11011 7 +b01100 6 +b11000 9 +b00000000000000000000000000011001 " +b11001 8 +#251 +#252 +#253 +#254 +#255 +0! +#256 +#257 +#258 +#259 +#260 +1! +b11000 8 +b00000000000000000000000000011010 " +b01100 9 +b00110 6 +b11001 7 +b11001 5 +#261 +#262 +#263 +#264 +#265 +0! +#266 +#267 +#268 +#269 +#270 +1! +b11000 5 +b11000 7 +b00011 6 +b00110 9 +b00000000000000000000000000011011 " +b01100 8 +#271 +#272 +#273 +#274 +#275 +0! +#276 +#277 +#278 +#279 +#280 +1! +b00110 8 +b00000000000000000000000000011100 " +b00011 9 +b10101 6 +b01100 7 +b01100 5 +#281 +#282 +#283 +#284 +#285 +0! +#286 +#287 +#288 +#289 +#290 +1! +b00110 5 +b00110 7 +b11110 6 +b10101 9 +b00000000000000000000000000011101 " +b00011 8 +#291 +#292 +#293 +#294 +#295 +0! +#296 +#297 +#298 +#299 +#300 +1! +b10101 8 +b00000000000000000000000000011110 " +b11110 9 +b01111 6 +b00011 7 +b00011 5 +#301 +#302 +#303 +#304 +#305 +0! +#306 +#307 +#308 +#309 +#310 +1! +b10101 5 +b10101 7 +b10011 6 +b01111 9 +b00000000000000000000000000011111 " +b11110 8 +#311 +#312 +#313 +#314 +#315 +0! +#316 +#317 +#318 +#319 +#320 +1! +b01111 8 +b00000000000000000000000000100000 " +b10011 9 +b11101 6 +b11110 7 +b11110 5 +#321 +#322 +#323 +#324 +#325 +0! +#326 +#327 +#328 +#329 +#330 +1! +b01111 5 +b01111 7 +b11010 6 +b11101 9 +b00000000000000000000000000100001 " +b10011 8 +#331 +#332 +#333 +#334 +#335 +0! +#336 +#337 +#338 +#339 +#340 +1! +b11101 8 +b00000000000000000000000000100010 " +b11010 9 +b01101 6 +b10011 7 +b10011 5 +#341 +#342 +#343 +#344 +#345 +0! +#346 +#347 +#348 +#349 +#350 +1! +b11101 5 +b11101 7 +b10010 6 +b01101 9 +b00000000000000000000000000100011 " +b11010 8 +#351 +#352 +#353 +#354 +#355 +0! +#356 +#357 +#358 +#359 +#360 +1! +b01101 8 +b00000000000000000000000000100100 " +b10010 9 +b01001 6 +b11010 7 +b11010 5 +#361 +#362 +#363 +#364 +#365 +0! +#366 +#367 +#368 +#369 +#370 +1! +b01101 5 +b01101 7 +b10000 6 +b01001 9 +b00000000000000000000000000100101 " +b10010 8 +#371 +#372 +#373 +#374 +#375 +0! +#376 +#377 +#378 +#379 +#380 +1! +b01001 8 +b00000000000000000000000000100110 " +b10000 9 +b01000 6 +b10010 7 +b10010 5 +#381 +#382 +#383 +#384 +#385 +0! +#386 +#387 +#388 +#389 +#390 +1! +b01001 5 +b01001 7 +b00100 6 +b01000 9 +b00000000000000000000000000100111 " +b10000 8 +#391 +#392 +#393 +#394 +#395 +0! +#396 +#397 +#398 +#399 +#400 +1! +b01000 8 +b00000000000000000000000000101000 " +b00100 9 +b00010 6 +b10000 7 +b10000 5 +#401 +#402 +#403 +#404 +#405 +0! +#406 +#407 +#408 +#409 +#410 +1! +b01000 5 +b01000 7 +b00001 6 +b00010 9 +b00000000000000000000000000101001 " +b00100 8 +#411 +#412 +#413 +#414 +#415 +0! +#416 +#417 +#418 +#419 +#420 +1! +b00010 8 +b00000000000000000000000000101010 " +b00001 9 +b10100 6 +b00100 7 +b00100 5 +#421 +#422 +#423 +#424 +#425 +0! +#426 +#427 +#428 +#429 +#430 +1! +b00010 5 +b00010 7 +b01010 6 +b10100 9 +b00000000000000000000000000101011 " +b00001 8 +#431 +#432 +#433 +#434 +#435 +0! +#436 +#437 +#438 +#439 +#440 +1! +b10100 8 +b00000000000000000000000000101100 " +b01010 9 +b00101 6 +b00001 7 +b00001 5 +#441 +#442 +#443 +#444 +#445 +0! +#446 +#447 +#448 +#449 +#450 +1! +b10100 5 +b10100 7 +b10110 6 +b00101 9 +b00000000000000000000000000101101 " +b01010 8 +#451 +#452 +#453 +#454 +#455 +0! +#456 +#457 +#458 +#459 +#460 +1! +b00101 8 +b00000000000000000000000000101110 " +b10110 9 +b01011 6 +b01010 7 +b01010 5 +#461 +#462 +#463 +#464 +#465 +0! +#466 +#467 +#468 +#469 +#470 +1! +b00101 5 +b00101 7 +b10001 6 +b01011 9 +b00000000000000000000000000101111 " +b10110 8 +#471 +#472 +#473 +#474 +#475 +0! +#476 +#477 +#478 +#479 +#480 +1! +b01011 8 +b00000000000000000000000000110000 " +b10001 9 +b11100 6 +b10110 7 +b10110 5 +#481 +#482 +#483 +#484 +#485 +0! +#486 +#487 +#488 +#489 +#490 +1! +b01011 5 +b01011 7 +b01110 6 +b11100 9 +b00000000000000000000000000110001 " +b10001 8 +#491 +#492 +#493 +#494 +#495 +0! +#496 +#497 +#498 +#499 +#500 +1! +b11100 8 +b00000000000000000000000000110010 " +b01110 9 +b00111 6 +b10001 7 +b10001 5 +#501 +#502 +#503 +#504 +#505 +0! +#506 +#507 +#508 +#509 +#510 +1! +b11100 5 +b11100 7 +b10111 6 +b00111 9 +b00000000000000000000000000110011 " +b01110 8 +#511 +#512 +#513 +#514 +#515 +0! +#516 +#517 +#518 +#519 +#520 +1! +b00111 8 +b00000000000000000000000000110100 " +b10111 9 +b11111 6 +b01110 7 +b01110 5 +#521 +#522 +#523 +#524 +#525 +0! +#526 +#527 +#528 +#529 +#530 +1! +b00111 5 +b00111 7 +b11011 6 +b11111 9 +b00000000000000000000000000110101 " +b10111 8 +#531 +#532 +#533 +#534 +#535 +0! +#536 +#537 +#538 +#539 +#540 +1! +b11111 8 +b00000000000000000000000000110110 " +b11011 9 +b11001 6 +b10111 7 +b10111 5 +#541 +#542 +#543 +#544 +#545 +0! +#546 +#547 +#548 +#549 +#550 +1! +b11111 5 +b11111 7 +b11000 6 +b11001 9 +b00000000000000000000000000110111 " +b11011 8 +#551 +#552 +#553 +#554 +#555 +0! +#556 +#557 +#558 +#559 +#560 +1! +b11001 8 +b00000000000000000000000000111000 " +b11000 9 +b01100 6 +b11011 7 +b11011 5 +#561 +#562 +#563 +#564 +#565 +0! +#566 +#567 +#568 +#569 +#570 +1! +b11001 5 +b11001 7 +b00110 6 +b01100 9 +b00000000000000000000000000111001 " +b11000 8 +#571 +#572 +#573 +#574 +#575 +0! +#576 +#577 +#578 +#579 +#580 +1! +b01100 8 +b00000000000000000000000000111010 " +b00110 9 +b00011 6 +b11000 7 +b11000 5 +#581 +#582 +#583 +#584 +#585 +0! +#586 +#587 +#588 +#589 +#590 +1! +b01100 5 +b01100 7 +b10101 6 +b00011 9 +b00000000000000000000000000111011 " +b00110 8 +#591 +#592 +#593 +#594 +#595 +0! +#596 +#597 +#598 +#599 +#600 +1! +b00011 8 +b00000000000000000000000000111100 " +b10101 9 +b11110 6 +b00110 7 +b00110 5 +#601 +#602 +#603 +#604 +#605 +0! +#606 +#607 +#608 +#609 +#610 +1! +b00011 5 +b00011 7 +b01111 6 +b11110 9 +b00000000000000000000000000111101 " +b10101 8 +#611 +#612 +#613 +#614 +#615 +0! +#616 +#617 +#618 +#619 +#620 +1! +b11110 8 +b00000000000000000000000000111110 " +b01111 9 +b10011 6 +b10101 7 +b10101 5 +#621 +#622 +#623 +#624 +#625 +0! +#626 +#627 +#628 +#629 +#630 +1! +b11110 5 +b11110 7 +b11101 6 +b10011 9 +b00000000000000000000000000111111 " +b01111 8 +#631 +#632 +#633 +#634 +#635 +0! +#636 +#637 +#638 +#639 +#640 +1! +b10011 8 +b00000000000000000000000001000000 " +b11101 9 +b11010 6 +b01111 7 +b01111 5 +#641 +#642 +#643 +#644 +#645 +0! +#646 +#647 +#648 +#649 +#650 +1! +b10011 5 +b10011 7 +b01101 6 +b11010 9 +b00000000000000000000000001000001 " +b11101 8 +#651 +#652 +#653 +#654 +#655 +0! +#656 +#657 +#658 +#659 +#660 +1! +b11010 8 +b00000000000000000000000001000010 " +b01101 9 +b10010 6 +b11101 7 +b11101 5 +#661 +#662 +#663 +#664 +#665 +0! +#666 +#667 +#668 +#669 +#670 +1! +b11010 5 +b11010 7 +b01001 6 +b10010 9 +b00000000000000000000000001000011 " +b01101 8 +#671 +#672 +#673 +#674 +#675 +0! +#676 +#677 +#678 +#679 +#680 +1! +b10010 8 +b00000000000000000000000001000100 " +b01001 9 +b10000 6 +b01101 7 +b01101 5 +#681 +#682 +#683 +#684 +#685 +0! +#686 +#687 +#688 +#689 +#690 +1! +b10010 5 +b10010 7 +b01000 6 +b10000 9 +b00000000000000000000000001000101 " +b01001 8 +#691 +#692 +#693 +#694 +#695 +0! +#696 +#697 +#698 +#699 +#700 +1! +b10000 8 +b00000000000000000000000001000110 " +b01000 9 +b00100 6 +b01001 7 +b01001 5 +#701 +#702 +#703 +#704 +#705 +0! +#706 +#707 +#708 +#709 +#710 +1! +b10000 5 +b10000 7 +b00010 6 +b00100 9 +b00000000000000000000000001000111 " +b01000 8 +#711 +#712 +#713 +#714 +#715 +0! +#716 +#717 +#718 +#719 +#720 +1! +b00100 8 +b00000000000000000000000001001000 " +b00010 9 +b00001 6 +b01000 7 +b01000 5 +#721 +#722 +#723 +#724 +#725 +0! +#726 +#727 +#728 +#729 +#730 +1! +b00100 5 +b00100 7 +b10100 6 +b00001 9 +b00000000000000000000000001001001 " +b00010 8 +#731 +#732 +#733 +#734 +#735 +0! +#736 +#737 +#738 +#739 +#740 +1! +b00001 8 +b00000000000000000000000001001010 " +b10100 9 +b01010 6 +b00010 7 +b00010 5 +#741 +#742 +#743 +#744 +#745 +0! +#746 +#747 +#748 +#749 +#750 +1! +b00001 5 +b00001 7 +b00101 6 +b01010 9 +b00000000000000000000000001001011 " +b10100 8 +#751 +#752 +#753 +#754 +#755 +0! +#756 +#757 +#758 +#759 +#760 +1! +b01010 8 +b00000000000000000000000001001100 " +b00101 9 +b10110 6 +b10100 7 +b10100 5 +#761 +#762 +#763 +#764 +#765 +0! +#766 +#767 +#768 +#769 +#770 +1! +b01010 5 +b01010 7 +b01011 6 +b10110 9 +b00000000000000000000000001001101 " +b00101 8 +#771 +#772 +#773 +#774 +#775 +0! +#776 +#777 +#778 +#779 +#780 +1! +b10110 8 +b00000000000000000000000001001110 " +b01011 9 +b10001 6 +b00101 7 +b00101 5 +#781 +#782 +#783 +#784 +#785 +0! +#786 +#787 +#788 +#789 +#790 +1! +b10110 5 +b10110 7 +b11100 6 +b10001 9 +b00000000000000000000000001001111 " +b01011 8 +#791 +#792 +#793 +#794 +#795 +0! +#796 +#797 +#798 +#799 +#800 +1! +b10001 8 +b00000000000000000000000001010000 " +b11100 9 +b01110 6 +b01011 7 +b01011 5 +#801 +#802 +#803 +#804 +#805 +0! +#806 +#807 +#808 +#809 +#810 +1! +b10001 5 +b10001 7 +b00111 6 +b01110 9 +b00000000000000000000000001010001 " +b11100 8 +#811 +#812 +#813 +#814 +#815 +0! +#816 +#817 +#818 +#819 +#820 +1! +b01110 8 +b00000000000000000000000001010010 " +b00111 9 +b10111 6 +b11100 7 +b11100 5 +#821 +#822 +#823 +#824 +#825 +0! +#826 +#827 +#828 +#829 +#830 +1! +b01110 5 +b01110 7 +b11111 6 +b10111 9 +b00000000000000000000000001010011 " +b00111 8 +#831 +#832 +#833 +#834 +#835 +0! +#836 +#837 +#838 +#839 +#840 +1! +b10111 8 +b00000000000000000000000001010100 " +b11111 9 +b11011 6 +b00111 7 +b00111 5 +#841 +#842 +#843 +#844 +#845 +0! +#846 +#847 +#848 +#849 +#850 +1! +b10111 5 +b10111 7 +b11001 6 +b11011 9 +b00000000000000000000000001010101 " +b11111 8 +#851 +#852 +#853 +#854 +#855 +0! +#856 +#857 +#858 +#859 +#860 +1! +b11011 8 +b00000000000000000000000001010110 " +b11001 9 +b11000 6 +b11111 7 +b11111 5 +#861 +#862 +#863 +#864 +#865 +0! +#866 +#867 +#868 +#869 +#870 +1! +b11011 5 +b11011 7 +b01100 6 +b11000 9 +b00000000000000000000000001010111 " +b11001 8 +#871 +#872 +#873 +#874 +#875 +0! +#876 +#877 +#878 +#879 +#880 +1! +b11000 8 +b00000000000000000000000001011000 " +b01100 9 +b00110 6 +b11001 7 +b11001 5 +#881 +#882 +#883 +#884 +#885 +0! +#886 +#887 +#888 +#889 +#890 +1! +b11000 5 +b11000 7 +b00011 6 +b00110 9 +b00000000000000000000000001011001 " +b01100 8 +#891 +#892 +#893 +#894 +#895 +0! +#896 +#897 +#898 +#899 +#900 +1! +b00110 8 +b00000000000000000000000001011010 " +b00011 9 +b10101 6 +b01100 7 +b01100 5 +#901 +#902 +#903 +#904 +#905 +0! +#906 +#907 +#908 +#909 +#910 +1! +b00110 5 +b00110 7 +b11110 6 +b10101 9 +b00000000000000000000000001011011 " +b00011 8 +#911 +#912 +#913 +#914 +#915 +0! +#916 +#917 +#918 +#919 +#920 +1! +b10101 8 +b00000000000000000000000001011100 " +b11110 9 +b01111 6 +b00011 7 +b00011 5 +#921 +#922 +#923 +#924 +#925 +0! +#926 +#927 +#928 +#929 +#930 +1! +b10101 5 +b10101 7 +b10011 6 +b01111 9 +b00000000000000000000000001011101 " +b11110 8 +#931 +#932 +#933 +#934 +#935 +0! +#936 +#937 +#938 +#939 +#940 +1! +b01111 8 +b00000000000000000000000001011110 " +b10011 9 +b11101 6 +b11110 7 +b11110 5 +#941 +#942 +#943 +#944 +#945 +0! +#946 +#947 +#948 +#949 +#950 +1! +b01111 5 +b01111 7 +b11010 6 +b11101 9 +b00000000000000000000000001011111 " +b10011 8 +#951 +#952 +#953 +#954 +#955 +0! +#956 +#957 +#958 +#959 +#960 +1! +b11101 8 +b00000000000000000000000001100000 " +b11010 9 +b01101 6 +b10011 7 +b10011 5 +#961 +#962 +#963 +#964 +#965 +0! +#966 +#967 +#968 +#969 +#970 +1! +b11101 5 +b11101 7 +b10010 6 +b01101 9 +b00000000000000000000000001100001 " +b11010 8 +#971 +#972 +#973 +#974 +#975 +0! +#976 +#977 +#978 +#979 +#980 +1! +b01101 8 +b00000000000000000000000001100010 " +b10010 9 +b01001 6 +b11010 7 +b11010 5 +#981 +#982 +#983 +#984 +#985 +0! +#986 +#987 +#988 +#989 +#990 +1! +b01101 5 +b01101 7 +b10000 6 +b01001 9 +b00000000000000000000000001100011 " +b10010 8 +#991 +#992 +#993 +#994 +#995 +0! +#996 +#997 +#998 +#999 +#1000 +1! +b01001 8 +b00000000000000000000000001100100 " +b10000 9 +b01000 6 +b10010 7 +b10010 5 +#1001 +#1002 +#1003 +#1004 diff --git a/test_regress/t/t_trace_fst_sc_cmake.pl b/test_regress/t/t_trace_fst_sc_cmake.pl new file mode 100755 index 000000000..9764d6bf0 --- /dev/null +++ b/test_regress/t/t_trace_fst_sc_cmake.pl @@ -0,0 +1,31 @@ +#!/usr/bin/env perl +# 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 + +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } + +scenarios(vlt_all => 1); + +if (!$Self->have_sc) { + skip("No SystemC installed"); +} +else { + compile( + verilator_flags2 => ["--trace-fst --sc"], + verilator_make_gmake => 0, + verilator_make_cmake => 1, + ); + + execute( + check_finished => 1, + ); + + fst_identical($Self->trace_filename, $Self->{golden_filename}); +} +ok(1); +1; diff --git a/test_regress/t/t_trace_fst_sc_cmake.v b/test_regress/t/t_trace_fst_sc_cmake.v new file mode 100644 index 000000000..52c148bd5 --- /dev/null +++ b/test_regress/t/t_trace_fst_sc_cmake.v @@ -0,0 +1,98 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// Author: Yu-Sheng Lin johnjohnlys@media.ee.ntu.edu.tw +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc; + reg rstn; + + parameter real fst_gparam_real = 1.23; + localparam real fst_lparam_real = 4.56; + real fst_real = 1.23; + integer fst_integer; + bit fst_bit; + logic fst_logic; + int fst_int; + shortint fst_shortint; + longint fst_longint; + byte fst_byte; + + parameter fst_parameter = 123; + localparam fst_lparam = 456; + supply0 fst_supply0; + supply1 fst_supply1; + tri0 fst_tri0; + tri1 fst_tri1; + tri fst_tri; + wire fst_wire; + + logic [4:0] state; + + Test test (/*AUTOINST*/ + // Outputs + .state (state[4:0]), + // Inputs + .clk (clk), + .rstn (rstn)); + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc==0) begin + // Setup + rstn <= ~'1; + end + else if (cyc<10) begin + rstn <= ~'1; + end + else if (cyc<90) begin + rstn <= ~'0; + end + else if (cyc==99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule + + +module Test ( + input clk, + input rstn, + output logic [4:0] state + ); + + logic [4:0] state_w; + logic [4:0] state_array [3]; + assign state = state_array[0]; + + always_comb begin + state_w[4] = state_array[2][0]; + state_w[3] = state_array[2][4]; + state_w[2] = state_array[2][3] ^ state_array[2][0]; + state_w[1] = state_array[2][2]; + state_w[0] = state_array[2][1]; + end + + always_ff @(posedge clk or negedge rstn) begin + if (!rstn) begin + for (int i = 0; i < 3; i++) + state_array[i] <= 'b1; + end + else begin + for (int i = 0; i < 2; i++) + state_array[i] <= state_array[i+1]; + state_array[2] <= state_w; + end + end + +endmodule diff --git a/test_regress/t/t_unpacked_str_init2.pl b/test_regress/t/t_unpacked_str_init2.pl new file mode 100755 index 000000000..235ca326a --- /dev/null +++ b/test_regress/t/t_unpacked_str_init2.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); + +# TODO change to compile() +lint( + ); + +# No execute, not self-checking + +ok(1); +1; diff --git a/test_regress/t/t_unpacked_str_init2.v b/test_regress/t/t_unpacked_str_init2.v new file mode 100644 index 000000000..9481aafb8 --- /dev/null +++ b/test_regress/t/t_unpacked_str_init2.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, 2018 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +// issue2895 + +module t (/*AUTOARG*/); + + localparam string REG_X [0:31] = '{"zero", "ra", "sp", "gp", "tp", "t0", + "t1", "t2", "s0/fp", "s1", "a0", "a1", + "a2", "a3", "a4", "a5", "a6", "a7", "s2", + "s3", "s4", "s5", "s6", "s7", "s8", "s9", + "s10", "s11", "t3", "t4", "t5", "t6"}; + + function string reg_x (logic [4:0] r, bit abi=1'b0); + reg_x = abi ? REG_X[r] : $sformatf("x%0d", r); + endfunction + + // the issue is triggered by a second function containing a case statement + function string f2 (logic [4:0] r, bit abi=0); + case (r) + 5'd0: f2 = $sformatf("nop"); + 5'd1: f2 = $sformatf("reg %s", reg_x(r[4:0], abi)); + default: f2 = $sformatf("ILLEGAL"); + endcase + endfunction + + initial begin + for (int unsigned i = 0; i < 32; ++i) begin + $display("REGX: %s", reg_x(i[4:0], 1'b1)); + end + $display("OP: %s", f2(5'd7)); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_vpi_get.cpp b/test_regress/t/t_vpi_get.cpp index fa97e5095..592246b3b 100644 --- a/test_regress/t/t_vpi_get.cpp +++ b/test_regress/t/t_vpi_get.cpp @@ -173,7 +173,7 @@ int mon_check_props() { {"sub.the_intf.bytesig", {8, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, {"sub.the_intf.param", {32, vpiNoDirection, 0, vpiParameter}, {0, 0, 0, 0}}, {"sub.the_intf.lparam", {32, vpiNoDirection, 0, vpiParameter}, {0, 0, 0, 0}}, - {"twobytwo", {2, vpiNoDirection, 0, vpiMemory}, {2, vpiNoDirection, 0, vpiMemoryWord}}, + {"twobytwo", {4, vpiNoDirection, 0, vpiReg}, {0, 0, 0, 0}}, {NULL, {0, 0, 0, 0}, {0, 0, 0, 0}}}; struct params* value = values; while (value->signal) { diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index c420baebc..3dc17b55a 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -33,6 +33,7 @@ #include "TestSimulator.h" #include "TestVpi.h" +#include "TestCheck.h" // __FILE__ is too long #define FILENM "t_vpi_memory.cpp" @@ -41,116 +42,103 @@ if (0) printf unsigned int main_time = 0; +int errors = 0; //====================================================================== -#define CHECK_RESULT_VH(got, exp) \ - if ((got) != (exp)) { \ - printf("%%Error: %s:%d: GOT = %p EXP = %p\n", FILENM, __LINE__, (got), (exp)); \ - return __LINE__; \ - } - -#define CHECK_RESULT_NZ(got) \ - if (!(got)) { \ - printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", FILENM, __LINE__); \ - return __LINE__; \ - } - -// Use cout to avoid issues with %d/%lx etc -#define CHECK_RESULT(got, exp) \ - if ((got) != (exp)) { \ - std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << ": GOT = " << (got) \ - << " EXP = " << (exp) << std::endl; \ - return __LINE__; \ - } - -#define CHECK_RESULT_HEX(got, exp) \ - if ((got) != (exp)) { \ - std::cout << std::dec << "%Error: " << FILENM << ":" << __LINE__ << std::hex \ - << ": GOT = " << (got) << " EXP = " << (exp) << std::endl; \ - return __LINE__; \ - } - -#define CHECK_RESULT_CSTR(got, exp) \ - if (strcmp((got), (exp))) { \ - printf("%%Error: %s:%d: GOT = '%s' EXP = '%s'\n", FILENM, __LINE__, \ - (got) ? (got) : "", (exp) ? (exp) : ""); \ - return __LINE__; \ - } - -#define CHECK_RESULT_CSTR_STRIP(got, exp) CHECK_RESULT_CSTR(got + strspn(got, " "), exp) - -int _mon_check_range(const TestVpiHandle& handle, int size, int left, int right) { +void _mon_check_range(const TestVpiHandle& handle, int size, int left, int right) { s_vpi_value value; value.format = vpiIntVal; value.value.integer = 0; // check size of object { int vpisize = vpi_get(vpiSize, handle); - CHECK_RESULT(vpisize, size); + TEST_CHECK_EQ(vpisize, size); } int coherency; { // check left hand side of range TestVpiHandle left_h = vpi_handle(vpiLeftRange, handle); - CHECK_RESULT_NZ(left_h); + TEST_CHECK_NZ(left_h); vpi_get_value(left_h, &value); - CHECK_RESULT(value.value.integer, left); + TEST_CHECK_EQ(value.value.integer, left); coherency = value.value.integer; } { // check right hand side of range TestVpiHandle right_h = vpi_handle(vpiRightRange, handle); - CHECK_RESULT_NZ(right_h); + TEST_CHECK_NZ(right_h); vpi_get_value(right_h, &value); - CHECK_RESULT(value.value.integer, right); + TEST_CHECK_EQ(value.value.integer, right); coherency -= value.value.integer; } // calculate size & check coherency = abs(coherency) + 1; - CHECK_RESULT(coherency, size); - return 0; // Ok + TEST_CHECK_EQ(coherency, size); } -int _mon_check_memory() { +void _mem_check(const char* name, int size, int left, int right, int words) { s_vpi_value value; - value.format = vpiIntVal; - value.value.integer = 0; s_vpi_error_info e; - vpi_printf((PLI_BYTE8*)"Check memory vpi ...\n"); - TestVpiHandle mem_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted("mem0"), NULL); - CHECK_RESULT_NZ(mem_h); - { - // check type - int vpitype = vpi_get(vpiType, mem_h); - CHECK_RESULT(vpitype, vpiMemory); + vpi_printf((PLI_BYTE8*)"Check memory vpi (%s) ...\n", name); + TestVpiHandle mem_h = vpi_handle_by_name((PLI_BYTE8*)TestSimulator::rooted(name), NULL); + TEST_CHECK_NZ(mem_h); + // check type + int vpitype = vpi_get(vpiType, mem_h); + if (vpitype != vpiMemory && vpitype != vpiReg) { + printf("%%Error: %s:%d vpiType neither vpiMemory or vpiReg: %d\n", FILENM, __LINE__, + vpitype); + errors++; + } + std::string binStr; + for (int i = words; i >= 1; i--) { + for (int pos = size - 1; pos >= 0; pos--) { + int posValue = (i >> pos) & 0x1; + binStr += posValue ? "1" : "0"; + } } - if (int status = _mon_check_range(mem_h, 16, 16, 1)) return status; // iterate and store - { + if (vpitype == vpiMemory) { + _mon_check_range(mem_h, words, words, 1); TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); int cnt = 0; while (TestVpiHandle lcl_h = vpi_scan(iter_h)) { + value.format = vpiIntVal; value.value.integer = ++cnt; vpi_put_value(lcl_h, &value, NULL, vpiNoDelay); + TEST_CHECK_Z(vpi_chk_error(&e)); // check size and range - if (int status = _mon_check_range(lcl_h, 32, 31, 0)) return status; + _mon_check_range(lcl_h, size, left, right); } iter_h.freed(); // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle - CHECK_RESULT(cnt, 16); // should be 16 addresses + TEST_CHECK_EQ(cnt, words); // should be words addresses + } else { + int expSize = size * words; + _mon_check_range(mem_h, expSize, expSize - 1, 0); + value.format = vpiBinStrVal; + value.value.str = const_cast(binStr.c_str()); + vpi_put_value(mem_h, &value, NULL, vpiNoDelay); + TEST_CHECK_Z(vpi_chk_error(&e)); } - { + if (vpitype == vpiMemory) { // iterate and accumulate TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); int cnt = 0; while (TestVpiHandle lcl_h = vpi_scan(iter_h)) { ++cnt; + value.format = vpiIntVal; vpi_get_value(lcl_h, &value); - CHECK_RESULT(value.value.integer, cnt); + TEST_CHECK_Z(vpi_chk_error(&e)); + TEST_CHECK_EQ(value.value.integer, cnt); } iter_h.freed(); // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle - CHECK_RESULT(cnt, 16); // should be 16 addresses + TEST_CHECK_EQ(cnt, words); // should be words addresses + } else { + value.format = vpiBinStrVal; + vpi_get_value(mem_h, &value); + TEST_CHECK_Z(vpi_chk_error(&e)); + TEST_CHECK_EQ(std::string(value.value.str), binStr); } // don't care for non verilator @@ -158,58 +146,77 @@ int _mon_check_memory() { if (TestSimulator::is_icarus()) { vpi_printf((PLI_BYTE8*)"Skipping property checks for simulator %s\n", TestSimulator::get_info().product); - return 0; // Ok + return; // Ok } { // make sure trying to get properties that don't exist // doesn't crash TestVpiHandle iter_h = vpi_iterate(vpiMemoryWord, mem_h); int should_be_0 = vpi_get(vpiSize, iter_h); - CHECK_RESULT(should_be_0, 0); + TEST_CHECK_EQ(should_be_0, 0); should_be_0 = vpi_get(vpiIndex, iter_h); - CHECK_RESULT(should_be_0, 0); + TEST_CHECK_EQ(should_be_0, 0); vpiHandle should_be_NULL = vpi_handle(vpiLeftRange, iter_h); - CHECK_RESULT(should_be_NULL, 0); + TEST_CHECK_EQ(should_be_NULL, 0); should_be_NULL = vpi_handle(vpiRightRange, iter_h); - CHECK_RESULT(should_be_NULL, 0); + TEST_CHECK_EQ(should_be_NULL, 0); should_be_NULL = vpi_handle(vpiScope, iter_h); - CHECK_RESULT(should_be_NULL, 0); + TEST_CHECK_EQ(should_be_NULL, 0); } - { + if (vpitype == vpiMemory) { // check vpiRange TestVpiHandle iter_h = vpi_iterate(vpiRange, mem_h); - CHECK_RESULT_NZ(iter_h); + TEST_CHECK_NZ(iter_h); TestVpiHandle lcl_h = vpi_scan(iter_h); - CHECK_RESULT_NZ(lcl_h); + TEST_CHECK_NZ(lcl_h); { TestVpiHandle side_h = vpi_handle(vpiLeftRange, lcl_h); - CHECK_RESULT_NZ(side_h); + TEST_CHECK_NZ(side_h); vpi_get_value(side_h, &value); - CHECK_RESULT(value.value.integer, 16); + TEST_CHECK_EQ(value.value.integer, 16); } { TestVpiHandle side_h = vpi_handle(vpiRightRange, lcl_h); - CHECK_RESULT_NZ(side_h); + TEST_CHECK_NZ(side_h); vpi_get_value(side_h, &value); - CHECK_RESULT(value.value.integer, 1); + TEST_CHECK_EQ(value.value.integer, 1); // check writing to vpiConstant vpi_put_value(side_h, &value, NULL, vpiNoDelay); - CHECK_RESULT_NZ(vpi_chk_error(&e)); + TEST_CHECK_NZ(vpi_chk_error(&e)); } { // iterator should exhaust after 1 dimension TestVpiHandle zero_h = vpi_scan(iter_h); iter_h.freed(); // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle - CHECK_RESULT(zero_h, 0); + TEST_CHECK_EQ(zero_h, 0); } } - return 0; // Ok +} + +struct params { + const char* name; + int size; + int left; + int right; + int words; +}; + +void _mon_check_memory() { + // See note in t_vpi_get.cpp about static + static struct params values[] + = {{"mem0", 32, 31, 0, 16}, {"memp32", 32, 31, 0, 16}, {"memp31", 31, 30, 0, 16}, + {"memp33", 33, 32, 0, 15}, {"memw", 32, 31, 0, 16}, {NULL, 0, 0, 0, 0}}; + struct params* value = values; + while (value->name) { + _mem_check(value->name, value->size, value->left, value->right, value->words); + value++; + } } int mon_check() { // Callback from initial block in monitor - if (int status = _mon_check_memory()) return status; - return 0; // Ok + _mon_check_memory(); + return errors; } //====================================================================== diff --git a/test_regress/t/t_vpi_memory.v b/test_regress/t/t_vpi_memory.v index c16a59cb5..ee99b1319 100644 --- a/test_regress/t/t_vpi_memory.v +++ b/test_regress/t/t_vpi_memory.v @@ -25,31 +25,42 @@ extern "C" int mon_check(); input clk; + typedef logic [31:0] word_t; reg [31:0] mem0 [16:1] /*verilator public_flat_rw @(posedge clk) */; + reg [16:1] [31:0] memp32 /*verilator public_flat_rw @(posedge clk) */; + reg [16:1] [30:0] memp31 /*verilator public_flat_rw @(posedge clk) */; + reg [15:1] [32:0] memp33 /*verilator public_flat_rw @(posedge clk) */; + word_t [16:1] memw /*verilator public_flat_rw @(posedge clk) */; integer i, status; +`define CHECK_MEM(mem, words) \ + for (i = words; i > 0; i--) \ + if (integer'(mem[i]) !== i) begin \ + $write("%%Error: %s[%d] : GOT = %d EXP = %d\n", `"mem`", i, mem[i], i); \ + status = -1; \ + end + // Test loop initial begin `ifdef VERILATOR status = $c32("mon_check()"); -`endif -`ifdef IVERILOG +`else 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); + $write("%%Error: t_vpi_memory.cpp: C Test failed (rc=%0d)\n", status); $stop; end - for (i = 16; i > 0; i--) - if (mem0[i] !== i) begin - $write("%%Error: %d : GOT = %d EXP = %d\n", i, mem0[i], i); - status = 1; - end + `CHECK_MEM(mem0, 16) + `CHECK_MEM(memp32, 16) + `CHECK_MEM(memp31, 16) + `CHECK_MEM(memp33, 15) + `CHECK_MEM(memw, 16) if (status!=0) begin - $write("%%Error: t_vpi_var.cpp:%0d: C Test failed\n", status); + $write("%%Error: Verilog memory checks failed\n"); $stop; end $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_vpi_module.cpp b/test_regress/t/t_vpi_module.cpp index 7c00dcbf5..2e9ca88e5 100644 --- a/test_regress/t/t_vpi_module.cpp +++ b/test_regress/t/t_vpi_module.cpp @@ -90,9 +90,12 @@ int mon_check() { // modDump(it, 0); // return 1; - TestVpiHandle topmod = vpi_scan(it); + TestVpiHandle topmod; + // both somepackage and t exist at the top level + while ((topmod = vpi_scan(it))) { + if (vpi_get(vpiType, topmod) == vpiModule) break; + } CHECK_RESULT_NZ(topmod); - CHECK_RESULT(vpi_get(vpiType, topmod), vpiModule); const char* t_name = vpi_get_str(vpiName, topmod); CHECK_RESULT_NZ(t_name); diff --git a/test_regress/t/t_vpi_module.pl b/test_regress/t/t_vpi_module.pl index bee11c3f0..a1835cb60 100755 --- a/test_regress/t/t_vpi_module.pl +++ b/test_regress/t/t_vpi_module.pl @@ -17,9 +17,8 @@ compile( make_top_shell => 0, make_main => 0, make_pli => 1, - iv_flags2 => ["-g2005-sv -D USE_VPI_NOT_DPI"], - v_flags2 => ["+define+USE_VPI_NOT_DPI"], - verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_module.cpp"], + iv_flags2 => ["-g2005-sv"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' +define+USE_DOLLAR_C32 --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_module.cpp"], ); execute( diff --git a/test_regress/t/t_vpi_module.v b/test_regress/t/t_vpi_module.v index ab6ac8201..b997270f1 100644 --- a/test_regress/t/t_vpi_module.v +++ b/test_regress/t/t_vpi_module.v @@ -6,9 +6,7 @@ // 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 +`ifndef IVERILOG import "DPI-C" context function int mon_check(); `endif @@ -21,7 +19,7 @@ module t (/*AUTOARG*/ clk ); -`ifdef VERILATOR +`ifdef USE_DOLLAR_C32 `systemc_header extern "C" int mon_check(); `verilog @@ -43,13 +41,11 @@ extern "C" int mon_check(); // Test loop initial begin -`ifdef VERILATOR - status = $c32("mon_check()"); -`endif `ifdef IVERILOG status = $mon_check(); -`endif -`ifndef USE_VPI_NOT_DPI +`elsif USE_DOLLAR_C32 + status = $c32("mon_check()"); +`else status = mon_check(); `endif if (status!=0) begin diff --git a/test_regress/t/t_vpi_module_dpi.pl b/test_regress/t/t_vpi_module_dpi.pl new file mode 100755 index 000000000..1a546432b --- /dev/null +++ b/test_regress/t/t_vpi_module_dpi.pl @@ -0,0 +1,34 @@ +#!/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/; + +VM_PREFIX("Vt_vpi_module"); +top_filename("t/t_vpi_module.v"); +pli_filename("t_vpi_module.cpp"); + +compile( + make_top_shell => 0, + make_main => 0, + make_pli => 1, + iv_flags2 => ["-g2005-sv"], + verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb' --exe --vpi --no-l2name $Self->{t_dir}/t_vpi_module.cpp"], + ); + +execute( + use_libvpi => 1, + check_finished => 1 + ); + +ok(1); +1; diff --git a/verilator-config.cmake.in b/verilator-config.cmake.in index cfd6ed2b2..c75e469d4 100644 --- a/verilator-config.cmake.in +++ b/verilator-config.cmake.in @@ -83,6 +83,12 @@ define_property(TARGET FULL_DOCS "Verilator multithreading enabled" ) +define_property(TARGET + PROPERTY VERILATOR_TRACE_THREADED + BRIEF_DOCS "Verilator multithread tracing enabled" + FULL_DOCS "Verilator multithread tracing enabled" +) + define_property(TARGET PROPERTY VERILATOR_COVERAGE BRIEF_DOCS "Verilator coverage enabled" @@ -113,9 +119,16 @@ define_property(TARGET FULL_DOCS "Verilator SystemC enabled" ) +define_property(TARGET + PROPERTY VERILATOR_TRACE_STRUCTS + BRIEF_DOCS "Verilator trace structs enabled" + FULL_DOCS "Verilator trace structs enabled" +) + + function(verilate TARGET) - cmake_parse_arguments(VERILATE "COVERAGE;TRACE;TRACE_FST;SYSTEMC" - "PREFIX;TOP_MODULE;THREADS;DIRECTORY" + cmake_parse_arguments(VERILATE "COVERAGE;TRACE;TRACE_FST;SYSTEMC;TRACE_STRUCTS" + "PREFIX;TOP_MODULE;THREADS;TRACE_THREADS;DIRECTORY" "SOURCES;VERILATOR_ARGS;INCLUDE_DIRS;OPT_SLOW;OPT_FAST;OPT_GLOBAL" ${ARGN}) if (NOT VERILATE_SOURCES) @@ -136,6 +149,10 @@ function(verilate TARGET) list(APPEND VERILATOR_ARGS --threads ${VERILATE_THREADS}) endif() + if (VERILATE_TRACE_THREADS) + list(APPEND VERILATOR_ARGS --trace-threads ${VERILATE_TRACE_THREADS}) + endif() + if (VERILATE_COVERAGE) list(APPEND VERILATOR_ARGS --coverage) endif() @@ -158,6 +175,10 @@ function(verilate TARGET) list(APPEND VERILATOR_ARGS --cc) endif() + if (VERILATE_TRACE_STRUCTS) + list(APPEND VERILATOR_ARGS --trace-structs) + endif() + foreach(INC ${VERILATE_INCLUDE_DIRS}) list(APPEND VERILATOR_ARGS -y "${INC}") endforeach() @@ -240,6 +261,11 @@ function(verilate TARGET) set_property(TARGET ${TARGET} PROPERTY VERILATOR_THREADED ON) endif() + if (${VERILATE_PREFIX}_TRACE_THREADS) + # If any verilate() call specifies TRACE_THREADS, define VL_TRACE_THREADED in the final build + set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_THREADED ON) + endif() + if (${VERILATE_PREFIX}_COVERAGE) # If any verilate() call specifies COVERAGE, define VM_COVERAGE in the final build set_property(TARGET ${TARGET} PROPERTY VERILATOR_COVERAGE ON) @@ -262,6 +288,10 @@ function(verilate TARGET) set_property(TARGET ${TARGET} PROPERTY VERILATOR_SYSTEMC ON) endif() + if (${VERILATE_PREFIX}_TRACE_STRUCTS) + set_property(TARGET ${TARGET} PROPERTY VERILATOR_TRACE_STRUCTS ON) + endif() + # Add the compile flags only on Verilated sources target_include_directories(${TARGET} PUBLIC ${VDIR}) target_sources(${TARGET} PRIVATE ${GENERATED_SOURCES} "${VCMAKE_COPY}" @@ -296,6 +326,7 @@ function(verilate TARGET) VM_COVERAGE=$> VM_SC=$> $<$>:VL_THREADED> + $<$>:VL_TRACE_THREADED> VM_TRACE=$> VM_TRACE_VCD=$> VM_TRACE_FST=$>